java自学网VIP

Java自学网

 找回密码
 立即注册

QQ登录

只需一步,快速开始

查看: 2515|回复: 0

《大规模分布式存储系统》第10章 数据库功能【10.2】

[复制链接]
  • TA的每日心情
    开心
    2021-5-25 00:00
  • 签到天数: 1917 天

    [LV.Master]出神入化

    2096

    主题

    3754

    帖子

    6万

    积分

    管理员

    Rank: 9Rank: 9Rank: 9

    积分
    66788

    宣传达人突出贡献优秀版主荣誉管理论坛元老

    发表于 2017-3-10 13:47:36 | 显示全部楼层 |阅读模式
    10.2 只读事务
    / c; J) h+ C& u" e% T只读事务(SELECT语句),经过词法分析、语法分析,预处理后,转化为逻辑+ }: N4 W# d" r: w/ y/ M( \, |
    查询计划和物理查询计划。以SQL语句select c1,c2 from t1 where id=1 group by c1
    3 m2 L5 B+ X( b8 {2 n; v  l) s1 Norder by c2为例,MergeServer收到该语句后将调用ObSql类的静态方法
    9 t* i7 ^7 s' r' q$ q7 M+ }) Fdirect_execute,执行步骤如下:
    * `4 o  |7 p$ M8 L% Q1)调用flex、bison解析SQL语句生成一个语法树。; h& e7 F) x3 x
    2)解析语法树,生成逻辑执行计划ObSelectStmt。ObSelectStmt结构中记录了" i6 Q9 ?) \8 l2 P% U  t  t
    SQL语句扫描的表格名(t1),投影列(c1,c2),过滤条件(id=1),分组列
    % h5 c2 z, [) K3 ~(c1)以及排序列(c2)。
    $ L, }4 [+ H! C% t: T3)根据逻辑执行计划生成物理执行计划。ObSelectStmt只是表达了一种意图,# {! X1 s% q: E7 b. g
    但并不知道实际如何执行,ObTransformer类的generate_physical_plan将ObSelectStmt转" z7 f: \+ h/ H' P6 @( A
    化为物理执行计划。
    8 E: X9 A# D+ b逻辑查询计划的改进以及物理查询计划的选择,即查询优化器,是关系数据库
    5 }) ]. s2 A6 a9 W4 j! V' @9 h6 B最难的部分,OceanBase目前在这一部分的工作不多。因此,本节不会涉及太多关于2 h5 r/ M# R6 B6 K3 H
    如何生成物理查询计划的内容,下面仅以两个例子说明OceanBase的物理查询计划。$ }- l' Q& R6 `, j" u
    例10-1 假设有一个单表SQL语句如图10-2所示。
    8 L: X3 _% G; X8 s. `6 P% G图 10-2 单表物理查询计划示例
    ! S, P8 q8 F% T# X5 s单表SQL语句执行过程如下:
    # t( ~1 M4 g$ E/ }  G/ b1)调用TableScan操作符,读取子表t1中的数据,该操作符还将执行投影
    # s9 [/ Q1 z5 p) F5 M(Project)和过滤(Filter),返回的结果只包含c3=10的数据行,且每行只包含c1、
    % J6 Z" S! j( w( T( Mc2、c3三列。
    * F( N2 |3 v$ ]# G3 T2)调用HashGroupBy操作符(假设采用基于哈希的分组算法),按照c1对数据$ E1 Q9 \" Q$ Z" h1 \
    分组,同时计算每个分组内c2列的总和。
    ; b1 C' m; g- w' Z. N3)调用Filter操作符,过滤分组后生成的结果,只返回上一层sum(c2)>=10的; _- l6 k5 l6 Z& b
    行。
    / w! p# c6 O4 u5 j4)调用Sort操作符将结果按照c1排序。
    - x3 U2 w6 K+ @# C$ H' @5)调用Project操作符,只返回c1和sum(c2)这两列数据。4 y' u1 X7 ?: J2 ?
    6)调用Limit操作符执行分页操作,只返回前20条数据。/ Y: |9 @& h! a& H) S
    例10-2 假设有一个需要联表的SQL语句如图10-3所示。
    + _4 d, u6 U! |, [4 w* L图 10-3 多表物理查询计划示例2 n) A" N! G' i
    多表SQL语句执行过程如下:! ]: N9 E8 j/ @/ J, Z
    1)调用TableScan分别读取t1和t2的数据。对于t1,使用条件c3=10对结果进行过
    $ Y1 y6 J& B6 j  j0 q6 j9 |7 `0 D1 r4 k滤,t1和t2都只需要返回c1,c2,c3这三列数据。: O6 w! ~9 @; u1 Q0 q
    2)假设采用基于排序的表连接算法,t1和t2分别按照t1.c2和t2.c2排序后,调用+ k7 Q/ e* p2 l# D1 P) M
    Merge Join运算符,以t1.c2=t2.c2为条件执行等值连接。
    + R9 y1 n$ v8 e  K6 i( l! B4 I3)调用HashGroupBy运算符(假设采用基于哈希的分组算法),按照t1.c1对数
    ; \8 ]) m9 C2 u* z# r1 p据分组,同时计算每个分组内t2.c3列的总和。
    + f( x- B5 l; a% @3 U. h; U4)调用Filter运算符,过滤分组后的生成的结果,只返回上一层sum(t2.c3)>- o/ P% _: f% j& ^
    =10的行。
    6 J1 ]+ h/ T2 b3 u  U5)调用Sort操作符将结果按照t1.c1排序。
    * [  X; q4 D8 C9 h6)调用Project操作符,只返回t1.c1和sum(t2.c3)这两列数据。
    . x% m  z$ b6 d0 [* U7)调用Limit操作符执行分页操作,只返回前20条数据。
    / m7 d& F. t, ^, B' v10.2.1 物理操作符接口
    6 T* {7 o  n, h" v% Q( z9.4.2节介绍一期分布式存储引擎中的迭代器接口为ObIterator,通过它,可以将
    % A. @# |, Y9 b% W7 N+ G读到的数据以cell为单位逐个迭代出来。然而,数据库操作总是以行为单位的,因/ S! j5 ~- p0 ]( B' c
    此,二期实现数据库功能层时考虑将基于cell的迭代器修改为基于行的迭代器。
    2 [8 m+ e5 x0 @* b5 \8 \, j行迭代器接口如下:* ~+ X8 m/ O( n: I, O
    //ObRow表示一行数据内容
    ( z3 X4 Q% Z. F: w) T6 Q" Fclass ObRow" L2 t: ]7 C! t/ H6 D% @
    {) @1 W6 F% U: B) Z/ S
    public:* P8 x$ F! K( z% X  ~  V7 }, j
    //根据表ID以及列ID获得指定cell3 j$ W# t% W- s' G4 r
    //@param[in]table_id表格ID
    9 S' ?( S, F2 a7 o$ N9 o* q% a//@param[in]column_id列ID
    4 G, F/ g) f* J9 a' @//@param[out]cell读到的cell: a% i+ M! _  b6 `" d( }3 e
    int get_cell(const uint64_t table_id,const uint64_t column_id,ObObj*&cell);/ |; z. X* p3 c- e
    //获取第cell_idx个cell+ l: C4 V- Y( f9 r+ ^
    int raw_get_cell(const int64_t cell_idx,const ObObj*&cell,uint64_t&table_id,, W0 r5 a& |( J; H- i& R& @, J
    uint64_t&column_id);4 y/ k! j( x4 }- f9 a& T3 J7 f
    //获取本行的列数
    ' I$ `" u8 I: @9 N( Bint64_t get_column_num()const;
    3 M- E8 \6 Z* i2 k8 ~- v/ S% R};
    ; D9 o7 u/ h/ o4 u0 V每一行数据(ObRow)包括多个列,每个列的内容包括所在的表
    & x; r! `5 [' @* ?% S% ?0 S4 BID(table_id),列ID(column_id)以及列内容(cell)。ObRow提供两种访问方
    8 S. K# E+ f4 C; x( @& \# r式:根据table_id和column_id随机访问某个列,以及根据列下标(cell_idx)获取某个
    - P0 S, V$ y4 I指定列。- D0 H1 Y% o6 I
    物理运算符接口如下:$ b  T8 |, M5 b
    //物理运算符接口
    2 X( T2 m* |, n5 b$ U8 ?& k& R* Xclass ObPhyOperator
    9 n$ l- s. r! A, U: B3 ~{
    2 C9 n5 Z  \( M9 h0 b. n5 {public:' i8 i! Q! k5 U+ r
    //添加子运算符,所有非叶子节点物理运算符都需要调用该接口8 h. S  n% F5 B8 F
    virtual int set_child(int32_t child_idx,ObPhyOperator&child_operator);
    ' @; i5 R4 k" W% A# g7 D//打开物理运算符。申请资源,打开子运算符等. x3 q# Y- l* }0 U, [$ x
    virtual int open()=0;. |. x9 |# F, x* L; k+ o+ }
    //关闭物理运算符。释放资源,关闭子运算符等
    9 W0 E, e9 X& q7 Dvirtual int close()=0;
    & p: I, j1 o: l4 _//获得下一行数据内容
    ' }+ x2 T" Q, ]//@param[out]row下一行数据内容的引用
    1 ~  h4 _9 M* }. h2 M//@return返回码,包括成功、迭代过程中出现错误以及迭代完成
    ( W9 M1 i) q/ k" t0 F# v# uvirtual int get_next_row(const ObRow*&row)=0;, ^' i% q: L+ m* y8 O$ N9 u
    };
    8 V+ l4 u  i. T! D$ l/ V3 J* T: AObPhyOperator每次获取一行数据,使用方法如下:6 c+ g1 v) ?- @$ D; K
    ObPhyOperator root_operator=root_operator_;//根运算符3 h3 ]/ A, M, L# h' s
    root_operator->open();
    $ G. X$ O5 a" K5 C3 C; E1 Y& n. WObRow*row=NULL;
    $ t, |  s' |4 z! `0 \8 y2 Rwhile(OB_SUCCESS==root_operator->get_next_row(row))
    / `( u  Y7 w: O$ o( @0 O) r{7 Y% `% D4 [6 C9 ^* k2 [
    Output(row);//输出本行
    & j2 R+ f) j: ?- Q4 d}
    : Y' K' ~, N4 h. O4 uroot_operator->close();
    4 L, J- V/ j7 L为什么ObPhyOperator类中有一个set_child接口呢?这是因为所有的物理运算符构7 _: @) X2 _  a; ~
    成一个树,每个物理运算的输出结果都可以认为是一个临时的二维表,树中孩子节
    9 g5 c! y+ n  a0 G. j* U5 M7 Z点的输出总是作为它的父亲节点的输入。例10-1中,叶子节点为一个TableScan类型: u7 O: `3 I) ~% `0 J8 y/ E2 w
    的物理运算符(称为table_scan_op),它的父亲节点为一个HashGroupBy类型的物理* v: v6 t6 \" E
    运算符(称为hash_group_by_op),接下来依次为Filter类型物理运算符filter_op,Sort
      f/ C! Y9 k  ^/ |! i* Q2 V类型物理运算符sort_op,Project类型物理运算符project_op,Limit类型物理运算符
    4 ^& @  L! J( x$ F9 {6 `$ A9 Wlimit_op。其中,limit_op为根运算符。那么,生成物理运算符时将执行如下语句:+ m5 N5 R" ]6 @9 \* z) r
    limit_op->set_child(0,project_op);! S2 v2 I6 a6 a# d8 G7 A+ O  s
    project_op->set_child(0,sort_op);5 |0 B( E. C5 g
    sort_op->set_child(0,filter_op);0 J7 c- x" j# r; M2 q- ?
    filter_op->set_child(0,hash_group_by_op);6 s+ a$ C; Z  Z
    hash_group_by_op->set_child(0,table_scan_op);) e; M0 J5 b9 Z9 L; O4 O# Z, B8 V
    root_op=limit_op;
    8 H4 {5 w/ C: K! @* }$ X, ZSQL最终执行时,只需要迭代root_op(即limit_op)就能够把需要的数据依次迭& `7 k9 ^  b" y
    代出来。limit_op发现前一批数据迭代完成则驱动下层的project_op获取下一批数据,
    : e% V3 V+ r2 r9 j( e: P, {) Xproject_op发现前一批数据迭代完成则驱动下层的sort_op获取下一批数据。以此类- W& N! j6 d& p1 ?8 L; W/ Q
    推,直到最底层的table_scan_op不断地从原始表t1中读取数据。# c: i4 {& W- F2 i# N  n
    10.2.2 单表操作9 p3 i+ Q' i( @3 R/ ?
    单表相关的物理运算符包括:7 r* u1 Q# \$ l- g: i' i* c
    ●TableScan:扫描某个表格,MergeServer将扫描请求发给请求的各个子表所在* ?! F. z6 p- N1 j+ \( Y
    的ChunkServer,并将ChunkServer返回的结果按照子表范围拼接起来作为输出。如果' X( Q- \0 K8 T7 s; p
    请求涉及多个子表,TabletScan可由多台ChunkServer并发执行。) _( e8 y* u; M8 G; C
    ●Filter:针对每行数据,判断是否满足过滤条件。& |1 z$ x) m6 f* F
    ●Projection:对输入的每一行,根据定义的输出表达式,计算输出结果行。
    $ ]$ z% f( r" f, c& L; p●GroupBy:把输入数据按照指定列进行聚集,对聚集后的每组数据可以执行计# r7 `7 X4 U1 W: @
    数(count)、求和(sum)、计算最小值(min)、计算最大值(max)、计算平均值: n. j. S1 F' E
    (avg)等聚集操作。
    & j. v7 o5 M0 h: x. K* Y●Sort:对输入数据进行整体排序,如果内存不够,需要使用外排序。
    & k* z3 n3 `& o0 ^6 F( z●Limit(offset,count):返回行号在[offset,offset+count)范围内的行。
    * A# X0 @& {2 q. S$ t●Distinct:消除某些列相同的重复行。: r- h  w+ R! X* u
    GroupBy、Distinct物理操作符可以通过基于排序的算法实现,也可以通过基于哈$ u' ^7 \4 l9 i  S5 o
    希的算法实现,分别对应HashGroupBy和MergeGroupBy,以及HashDistinct和# F, n  `. q0 R
    MergeDistinct。下面分别讨论排序算法和哈希算法。7 ~2 v9 |1 t4 u/ S& g: s5 r' N
    1.排序算法
      O* \: G  b8 U5 J7 YMergeGroupBy、MergeDistinct以及Sort都需要使用排序算法。通用的<key,value
    . |' _, ?; j/ k' t>排序器可以分为两个阶段:
    . [9 q7 A% a% c' X9 Q0 ?& J●数据收集:在数据收集阶段,调用者将<key,value>对依次加入到排序器。如
    % K! J4 r$ z) G, {  C# S* x  t* U果数据总量超过排序器的内存上限,需要首先将内存中的数据排好序,并存储到外' _/ a) l% p& Q( B, ~% O
    部磁盘中。
    & O1 x7 x& b$ Z●迭代输出:迭代第一行数据时,内存中可能有一部分未排序的数据,磁盘中也
    * Q+ a* A. n; S' @可能有几路已经排好序的数据。因此,首先将内存中的数据排好序。如果数据总量! `' I0 D4 p0 N- d' `( _+ a: ^
    不超过排序器内存上限,那么将内存中已经排好序的数据按行迭代输出(内排
    5 u5 L1 x! @5 {序);否则,对内存和磁盘中的部分有序数据执行多路归并,一边归并一边将结果8 P' Z7 Z- q* G: q
    迭代输出。; F4 D' z/ z: U
    2.哈希算法
    : p  ]+ I: T: X- _HashGroupBy以及HashDistinct都需要使用哈希算法。假设需要对<key,value>对5 u8 N6 o! \1 Q) x8 s
    按照key分组,那么首先使用key计算哈希值K,并将这个<key,value>对写入到第K个' Z" b3 Z* z2 t7 l4 k
    桶中。不同的key可能对应相同的哈希桶,因此,还需要对每个哈希桶内的<
    / c8 O+ o1 }. Y$ [3 \, Y& [# Dkey,value>对排序,这样才能使得key相同的元组能够连续迭代出来。哈希算法的难8 C) D" g9 H3 X5 E7 s8 n2 ^
    点在于数据总量超过内存上限的处理,由于篇幅有限,请自行思考。5 j0 T1 _/ l- |  I' B8 F
    10.2.3 多表操作& P+ w5 K) x: Z/ t# g! Z; R
    多表相关的物理操作符主要是Join。最为常见的Join类型包括两种:内连接
    + n' t* f1 |9 y2 T5 U  g& v4 U0 F(Inner Join)和左外连接(Left Outer Join),而且基本都是等值连接。如果需要连接/ S. n' F0 r% _$ @% K
    多张表,可以先连接前两张表,再将前两张表连接生成的结果(相当于一张临时0 b$ ~# Q0 V4 B. c) X, P
    表)与第三张表格连接,以此类推。
    5 H2 M( b: o9 z两张表实现等值连接方式主要分为两类:基于排序的算法(MergeJoin)以及基2 g! ~3 j* j2 y8 f$ S) X
    于哈希的算法(HashJoin)。对于MergeJoin,首先使用Sort运算符分别对输入表格预
    0 S8 B/ g/ Z- C9 O& U$ b1 l+ h8 `处理,使得两张输入表都在连接列上排好序,接着按顺序迭代两张输入表,合并连* _4 F+ F- o4 m; l
    接列相同的行并输出;对于HashJoin,首先根据连接列计算哈希值K,并分别将两张+ q" Z3 Y7 c! ~  A1 ^' h
    输入表格的数据写入到第K个桶中。接着,对每个哈希桶按照连接列排序。最后,依
    # G- a. Z% S2 M- s  P) {次对每个哈希桶合并连接列相同的行并输出。
    : Y$ P+ M) `0 }% ]子查询分为两种:关联子查询和非关联子查询,其中比较常用的是使用IN子句
    % l8 E9 Z5 W8 d) g2 a的非关联子查询。举例如下:
    ' _! d7 A6 m2 ?& J+ t% O  L6 {例10-3 假设有两张表格:item(商品表,包括商品号item_id,商品名5 b) I% ^/ p) q) E( L" r2 x; D  n, `& l
    item_name,分类号category_id,),category(类别表,包括分类号category_id,分" k* K# d, a! ?
    类名category_name)。如果需要查询分类号出现在category表中商品,可以采用图10-' V. N8 h: G' c' b
    4左边的IN子查询,而这个子查询将被自动转化为图10-4右边的等值连接。如果$ @7 m$ z8 C; S2 Q# ~
    category表中的category_id列有重复,表连接之前还需要使用distinct运算符来删除重
    - s. L1 q8 s% U& H# L) U( T+ H6 j复的记录。
    & @; _5 j" D/ O图 10-4 IN子查询转化为等值连接
    % h" y3 A, V  {例10-4 例10-3中,如果category表只包含category_id为1~10的记录,那么,可7 w7 ?  J0 O. a, [( ?) d
    以将IN子查询写成图10-5中的常量表达式。
    1 H8 R- x9 e) U. S4 v图 10-5 IN子查询转化为常量表达式
    + g4 u" M2 ~9 ], r转化为常量表达式后,MergeServer执行SQL计算时,可以将IN后面的常量列表
    " P' H' u. @) q4 z$ |发送给ChunkServer,ChunkServer只返回category_id在常量列表中的商品记录,而不是
    ) p( \6 K8 _) R将所有的记录返回给MergeServer过滤,从而减少二者之间传输的数据量。
    $ n+ h# P7 n, x) v$ ^OceanBase多表操作做得还很粗糙,例如不支持嵌套连接(Nested Loop Join),
    ! s% K- T/ w* M4 S" j不支持非等值连接,不支持查询优化等,后续将在合适的时间对这一部分代码进行# i1 X( C/ D4 ?/ V) N$ N4 a
    重构。! h+ F+ f6 b4 y) t
    10.2.4 SQL执行本地化/ E. l3 v: j  q5 {0 o4 I( U
    MergeServer包含SQL执行模块MS-SQL,ChunkServer也包含SQL执行模块CS-5 ^8 Z6 ~; c" P* \$ t
    SQL,那么,如何区分二者的功能呢?多表操作由MergeServer执行,对于单表操
    . o% t. _/ L( Z作,OceanBase设计的基本原则是尽量支持SQL计算本地化,保持数据节点与计算节
    # j5 D# y9 D4 z% O6 |点一致,也就是说,只要ChunkServer能够实现的操作,原则上都应该由它来完成。
    9 t4 L- m. H- E8 C' S- @& }  T●TableScan:每个ChunkServer扫描各自子表范围内的数据,由MergeServer合并- I5 o5 I% u9 n- N9 X
    ChunkServer返回的部分结果。
    ) }+ n4 ~9 r# y●Filter:对基本表的过滤集成在TableScan操作符中,由ChunkServer完成。对分, u7 G0 D* w- p0 z, @3 y5 L
    组后的结果执行过滤(Having)集成在GroupBy操作符中,一般情况下由MergeServer/ z/ K* y+ F1 V& ]
    完成;但是,如果能够确定每个分组的所有数据行只属于同一个子表,比如SQL请求" B8 p6 I% u4 @- t
    只涉及一个tablet,那么,分组以及分组后的过滤操作符可以由ChunkServer完成。6 w$ y# k" |8 _, @. p9 \! F
    ●Projection:对基本表的投影集成在TableScan操作符中,由ChunkServer完成,
    9 W# Q  a0 ~, d7 j对最终结果的投影由MergeServer完成。8 \# Q( C8 c# H1 f; l0 B% f/ d
    ●GroupBy:如果SQL读取的数据只在一个子表上,那么由该子表所在的/ f* p) \% j# s) h2 I, ]9 Q) L# c
    ChunkServer完成分组操作;否则,每台ChunkServer各自完成部分数据的分组操作,
    3 }& V% Z; Y0 @执行聚合运算后得到部分结果,再由MergeServer合并所有ChunkServer返回的部分结
    + j% B, g% ]( E- n* ?果,对于属于同一个分组的数据再次执行聚合运算。某些聚合运算需要做特殊处8 Z! u0 E9 R- y" C0 m
    理,比如avg,需要转化为sum和count操作发送给ChunkServer,MergeServer合并- C# A5 A. @# M; g
    ChunkServer返回的部分结果后计算出最终的sum和count值,并通过sum/count得到avg
    * a" B' e# M  }# j1 Y3 ]的最终结果。  Z/ V3 g+ p4 J) z
    ●Sort:如果SQL读取的数据只在一个子表上,那么由该子表所在的ChunkServer
    ; ]" \0 k/ n: Q0 A! k完成排序操作;否则,每台ChunkServer各自完成部分数据的排序,并将排好序的部. T. S+ @4 W5 g, f) y4 z" |, ~
    分数据返回MergeServer,再由MergeServer执行多路归并。
    8 v8 R" u% g) W$ R; J6 W4 H●Limit:Limit操作一般由MergeServer完成,但是,如果请求的数据只在一个子" q( D/ l/ [5 q$ Z, I
    表上,可以由ChunkServer完成,这往往会大大减少MergeServer与ChunkServer之间传" d' @. |4 ?2 o# Y, T
    输的数据量。0 b' J5 H/ J4 T6 }6 _
    ●Distinct:Distinct与GroupBy类似。ChunkServer先完成部分数据的去重,再由3 g& c# `2 z# M
    MergeServer进行整体去重。( a+ l+ ?/ G& W
    例10-5 图10-2中的SQL语句为"select c1,sum(c2)from t1 where c3=10 group
    / j  a0 |6 n5 _! z/ r  ?by c1 having sum(c2)>=10 order by c1 limit 0,20"。执行步骤如下:; b  V. c4 I3 f/ n6 P2 A, I0 e
    1)ChunkServer调用TableScan操作符,读取子表t1中的数据,该操作符还将执行
    : ^) E: H: u, F# }投影(Project)和过滤(Filter),返回的结果只包含c3=10的数据行,且每行只包含  }& Y0 W/ g8 l- l) }  \
    c1、c2、c3三列。
    ' }5 M- y  q! f$ I2 N9 g2)ChunkServer调用HashGroupBy操作符(假设采用基于哈希的分组算法),按1 x! {- G2 a0 z; P. d
    照c1对数据分组,同时计算每个分组内c2列的总和sum(c2)。
    - p% p# I' z0 o" J3)每个ChunkServer将分组后的部分结果返回MergeServer,MergeServer将来自不+ Q/ o; P3 n" t* l
    同ChunkServer的c1列相同的行合并在一起,再次执行sum运算。# C& G# V/ A2 B
    4)MergeServer调用Filter操作符,过滤第3)步生成的最终结果,只返回! m6 \1 L4 q  }3 J) l5 g( T+ n
    sum(c2)>=10的行。* `5 o% p# @" g$ x3 a2 A9 z
    5)MergeServer调用Sort操作符将结果按照c1排序。
    " e' O( ?5 f2 k. N6)MergeServer调用Project操作符,只返回c1和sum(c2)这两列数据。- t9 t) `5 I5 |$ H
    7)MergeServer调用Limit操作符执行分页操作,只返回前20条数据。; h& K' m) n& C! E- p7 _7 n
    当然,如果能够确定请求的数据全部属于同一个子表,那么,所有的物理运算1 s6 V" G7 l& g4 U
    符都可以由ChunkServer执行,MergeServer只需要将ChunkServer计算得到的结果转发6 ~0 c/ @5 A4 Y3 E4 x% j
    给客户端。9 f9 y* c) T. f% s8 d& j* s
    9 I7 U/ Q. _* a0 e6 D* ^

    6 ]- g( Y1 W/ |
    回复

    使用道具 举报

    您需要登录后才可以回帖 登录 | 立即注册

    本版积分规则

    QQ|Archiver|手机版|小黑屋|Java自学网

    GMT+8, 2025-4-1 13:46 , Processed in 0.316621 second(s), 33 queries .

    Powered by Javazx

    Copyright © 2012-2022, Javazx Cloud.

    快速回复 返回顶部 返回列表