java自学网VIP

Java自学网

 找回密码
 立即注册

QQ登录

只需一步,快速开始

查看: 2386|回复: 0

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

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

    [LV.Master]出神入化

    2025

    主题

    3683

    帖子

    6万

    积分

    管理员

    Rank: 9Rank: 9Rank: 9

    积分
    66345

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

    发表于 2017-3-10 13:47:36 | 显示全部楼层 |阅读模式
    10.2 只读事务7 n$ F: T( k( ^
    只读事务(SELECT语句),经过词法分析、语法分析,预处理后,转化为逻辑
    ( _. y- u' x" v) k) Z/ d查询计划和物理查询计划。以SQL语句select c1,c2 from t1 where id=1 group by c15 P4 I3 T! }( M" B  F
    order by c2为例,MergeServer收到该语句后将调用ObSql类的静态方法
    2 L2 d% V4 W- hdirect_execute,执行步骤如下:
    $ m+ a8 }4 G- f! ^  c* ~, s$ U- X5 [1)调用flex、bison解析SQL语句生成一个语法树。
    $ z: @+ W% s+ @# p" e2)解析语法树,生成逻辑执行计划ObSelectStmt。ObSelectStmt结构中记录了1 S# S- T+ ~( |0 m1 j3 O' l* \2 F: q! U
    SQL语句扫描的表格名(t1),投影列(c1,c2),过滤条件(id=1),分组列
      w' v4 @' k, n3 s) h$ j(c1)以及排序列(c2)。& U7 l( ~) t8 e5 t
    3)根据逻辑执行计划生成物理执行计划。ObSelectStmt只是表达了一种意图,: s/ |" x( h7 b( d4 q
    但并不知道实际如何执行,ObTransformer类的generate_physical_plan将ObSelectStmt转. C: C; f1 R5 b
    化为物理执行计划。
    4 K7 d: E% b2 w+ l0 p, e0 t逻辑查询计划的改进以及物理查询计划的选择,即查询优化器,是关系数据库; \7 y/ B0 o& I5 R5 P; _# N
    最难的部分,OceanBase目前在这一部分的工作不多。因此,本节不会涉及太多关于
    : a  Q( F6 @" g7 b2 r  q/ \5 f如何生成物理查询计划的内容,下面仅以两个例子说明OceanBase的物理查询计划。% l6 K+ S' @, W+ m3 _
    例10-1 假设有一个单表SQL语句如图10-2所示。3 m1 S8 O/ ^# z* B
    图 10-2 单表物理查询计划示例1 C- v; I9 H7 `
    单表SQL语句执行过程如下:
    % a0 ~( Q: m, c6 A1)调用TableScan操作符,读取子表t1中的数据,该操作符还将执行投影
    ! I+ w/ `! j9 f) b$ S! o(Project)和过滤(Filter),返回的结果只包含c3=10的数据行,且每行只包含c1、
    2 ~0 A6 p. [$ `- [0 Sc2、c3三列。
    * p) O+ k/ {! T3 u  V) J0 M! q  e' J2)调用HashGroupBy操作符(假设采用基于哈希的分组算法),按照c1对数据
    " C  k5 Q$ @1 \5 X分组,同时计算每个分组内c2列的总和。
    $ c! H$ w; G6 E6 b3)调用Filter操作符,过滤分组后生成的结果,只返回上一层sum(c2)>=10的
    - r$ u+ w6 L7 a' `, \行。3 N! Z2 M/ r/ f) C# F) C& t8 F
    4)调用Sort操作符将结果按照c1排序。
    9 t7 a3 V" X$ D& v* d5)调用Project操作符,只返回c1和sum(c2)这两列数据。: t3 `3 L- w, X: s! V1 i0 w( s
    6)调用Limit操作符执行分页操作,只返回前20条数据。
    * @2 z; H1 ]+ i3 n5 R/ f9 K4 y例10-2 假设有一个需要联表的SQL语句如图10-3所示。
    4 T8 [! S) h) m" M图 10-3 多表物理查询计划示例( K" m8 d' x* A3 G' S3 s, k$ V3 ^; d
    多表SQL语句执行过程如下:& M9 k  x  C+ L$ p; g; M: x7 @
    1)调用TableScan分别读取t1和t2的数据。对于t1,使用条件c3=10对结果进行过3 _% k0 C9 d- |/ J
    滤,t1和t2都只需要返回c1,c2,c3这三列数据。
    / h4 u) ^# j- B$ I* s* V' `  K! H2)假设采用基于排序的表连接算法,t1和t2分别按照t1.c2和t2.c2排序后,调用8 T9 s3 `/ [  f5 i9 Y
    Merge Join运算符,以t1.c2=t2.c2为条件执行等值连接。
    % w6 l5 P( {  Z3)调用HashGroupBy运算符(假设采用基于哈希的分组算法),按照t1.c1对数/ c5 i0 H( o; G4 h
    据分组,同时计算每个分组内t2.c3列的总和。
    1 A, t; ?2 P9 u4 n8 d7 n) S4)调用Filter运算符,过滤分组后的生成的结果,只返回上一层sum(t2.c3)>) V2 _- ^" z3 E1 e
    =10的行。
      O; Z/ ]2 l6 s$ X* A5)调用Sort操作符将结果按照t1.c1排序。
    & P) R% Z# p# V6)调用Project操作符,只返回t1.c1和sum(t2.c3)这两列数据。; |* E" q3 P7 P2 q/ P+ v
    7)调用Limit操作符执行分页操作,只返回前20条数据。/ t; M( M1 C6 t2 h" G
    10.2.1 物理操作符接口
    " B3 D$ [0 y' w9.4.2节介绍一期分布式存储引擎中的迭代器接口为ObIterator,通过它,可以将2 ^$ ]' j/ a8 M6 c& u$ F
    读到的数据以cell为单位逐个迭代出来。然而,数据库操作总是以行为单位的,因1 B" b) \0 x  F; R! Y1 Z
    此,二期实现数据库功能层时考虑将基于cell的迭代器修改为基于行的迭代器。; k; v9 f8 I; _% P
    行迭代器接口如下:
    6 ?( k- `1 ~( c" ]0 u* h' J4 m$ w" r//ObRow表示一行数据内容
    1 C0 X5 M2 ~8 j5 q3 k1 Gclass ObRow
    ( p" t/ G5 M# {- B% D: i( f{
    # [  S% R. [- z" [$ `2 `6 _9 Apublic:) A- w! n# B7 d" p0 ~5 Y
    //根据表ID以及列ID获得指定cell
    - _- _" q2 N! {1 \//@param[in]table_id表格ID$ u( m  D: l$ u" e, L
    //@param[in]column_id列ID
    ; O& ?3 g) E8 B) U  o//@param[out]cell读到的cell
      r# Z+ p5 G" N$ a, d0 Hint get_cell(const uint64_t table_id,const uint64_t column_id,ObObj*&cell);
    + X9 M* F- B) @. e* D. D  f  I//获取第cell_idx个cell6 Q4 _$ [- w8 {
    int raw_get_cell(const int64_t cell_idx,const ObObj*&cell,uint64_t&table_id,. D6 w$ j9 K! o8 L+ ]0 F
    uint64_t&column_id);
    7 y( C! W7 Q/ j. E, z1 ]9 g' S1 N//获取本行的列数9 f, r# W& b9 K: l
    int64_t get_column_num()const;$ z: T  |" n5 f) [3 O/ c0 F$ d
    };7 D7 B9 r4 |% F$ b
    每一行数据(ObRow)包括多个列,每个列的内容包括所在的表
    $ Y1 J8 C4 Y+ I  z9 b7 X  MID(table_id),列ID(column_id)以及列内容(cell)。ObRow提供两种访问方+ b& q) {* D9 ~+ J3 c
    式:根据table_id和column_id随机访问某个列,以及根据列下标(cell_idx)获取某个6 Z; J5 o$ x+ U8 G/ J/ E
    指定列。
    $ o; {+ [5 x5 U物理运算符接口如下:% @+ t0 p) ?8 Z5 ~
    //物理运算符接口
    1 {0 M6 W0 I0 k6 X. c9 T+ Eclass ObPhyOperator
    ) r, r7 `  W; M, t6 p; x' `0 a4 o{
    & {& g5 m7 D4 s2 Q+ `public:8 q6 j  i, [; t2 g
    //添加子运算符,所有非叶子节点物理运算符都需要调用该接口5 w+ P7 P! Q4 X) T  |1 a, S
    virtual int set_child(int32_t child_idx,ObPhyOperator&child_operator);
    5 E( I" n, W4 i! j' B$ b0 d//打开物理运算符。申请资源,打开子运算符等  {9 s: d6 i% `; b% w0 {
    virtual int open()=0;
    5 s( E9 K; p3 ~9 r" W' I$ A- m//关闭物理运算符。释放资源,关闭子运算符等% a, c$ L8 N! Z
    virtual int close()=0;
    4 @% v7 L- B5 c1 d7 ?//获得下一行数据内容
    + Q- E& |* f" E+ x1 E  ]$ O//@param[out]row下一行数据内容的引用
    % O3 ]% n' t! s  K! p//@return返回码,包括成功、迭代过程中出现错误以及迭代完成# F$ p; y: k( _. V+ ^
    virtual int get_next_row(const ObRow*&row)=0;# ^3 R* b+ ~" H6 T
    };
    / n9 y$ G# p: S$ K) k8 NObPhyOperator每次获取一行数据,使用方法如下:. P8 Q7 w8 S* Q
    ObPhyOperator root_operator=root_operator_;//根运算符( C& [* g5 `6 u6 t% P, L  [
    root_operator->open();
    - X% ]3 H7 ~4 e8 f; ]' lObRow*row=NULL;
    & H" W: `. v3 V% g" e$ N- _while(OB_SUCCESS==root_operator->get_next_row(row))& H) V6 ~, [0 V, u
    {
    & \5 F& Z2 {+ y$ oOutput(row);//输出本行
    / V9 ]5 J# c. m* o: A& F# _}
    5 Q" R  [) `0 j6 A9 ~root_operator->close();6 I' f! v- }5 E- H+ x
    为什么ObPhyOperator类中有一个set_child接口呢?这是因为所有的物理运算符构
    & C. g( Q4 `  {6 K' t7 |- }) {成一个树,每个物理运算的输出结果都可以认为是一个临时的二维表,树中孩子节
    1 G- P5 o: Y& K- r6 S/ Y1 A' N/ b点的输出总是作为它的父亲节点的输入。例10-1中,叶子节点为一个TableScan类型' i- b! K$ z3 \1 b7 j5 m; u
    的物理运算符(称为table_scan_op),它的父亲节点为一个HashGroupBy类型的物理- P2 G. N3 E! M0 V$ \- y6 ?: m* P
    运算符(称为hash_group_by_op),接下来依次为Filter类型物理运算符filter_op,Sort
    ) S  H$ s& {% Z! u: j类型物理运算符sort_op,Project类型物理运算符project_op,Limit类型物理运算符. d0 M2 m* W* |' z# R
    limit_op。其中,limit_op为根运算符。那么,生成物理运算符时将执行如下语句:
    - X- @; N- c4 I9 k" nlimit_op->set_child(0,project_op);
    " ]4 d5 [3 p& G# h3 Hproject_op->set_child(0,sort_op);
    " W/ W) D. {8 j- z7 P9 o+ usort_op->set_child(0,filter_op);
    ! L  j9 E- ?0 e6 y/ Efilter_op->set_child(0,hash_group_by_op);
    $ a2 F+ X3 q5 d3 x- W" }  A2 yhash_group_by_op->set_child(0,table_scan_op);
    7 J/ ~: K9 E' Z7 rroot_op=limit_op;
    & G1 t! m8 K) L- f& r; l* nSQL最终执行时,只需要迭代root_op(即limit_op)就能够把需要的数据依次迭
    $ d# d6 {1 Y* |; _  q1 W7 D$ P代出来。limit_op发现前一批数据迭代完成则驱动下层的project_op获取下一批数据,
    : A9 W; N/ v& R  }) c  _project_op发现前一批数据迭代完成则驱动下层的sort_op获取下一批数据。以此类
    0 h; O$ m% v! t; q推,直到最底层的table_scan_op不断地从原始表t1中读取数据。  i6 S! m& K1 e
    10.2.2 单表操作
    ( F0 B# w3 o( [/ t6 r4 T# ?; F单表相关的物理运算符包括:
    5 O6 k' a  g( B( e6 K●TableScan:扫描某个表格,MergeServer将扫描请求发给请求的各个子表所在
    ) p, q4 Y# ]5 x/ _的ChunkServer,并将ChunkServer返回的结果按照子表范围拼接起来作为输出。如果
    / U5 ?, D$ O# R请求涉及多个子表,TabletScan可由多台ChunkServer并发执行。! P8 W2 |* P' q% Z5 O0 d+ y5 S
    ●Filter:针对每行数据,判断是否满足过滤条件。
    : c/ [' m; b. W6 r; Z- ]2 B4 t$ v●Projection:对输入的每一行,根据定义的输出表达式,计算输出结果行。
    3 @  J2 ^1 ]) H$ o●GroupBy:把输入数据按照指定列进行聚集,对聚集后的每组数据可以执行计
    ' a0 L7 M, I# E4 X数(count)、求和(sum)、计算最小值(min)、计算最大值(max)、计算平均值
    0 J" L/ W: }# d0 X(avg)等聚集操作。
    7 M/ k0 Q7 H3 R' ?  i% m6 ~0 g●Sort:对输入数据进行整体排序,如果内存不够,需要使用外排序。5 r- a* \3 C" P4 A1 K5 k3 k
    ●Limit(offset,count):返回行号在[offset,offset+count)范围内的行。
    8 c  x& F: F; E% ~9 R●Distinct:消除某些列相同的重复行。! v% S7 F1 e/ `" D: }0 u
    GroupBy、Distinct物理操作符可以通过基于排序的算法实现,也可以通过基于哈! d' ]) z0 J9 n5 M
    希的算法实现,分别对应HashGroupBy和MergeGroupBy,以及HashDistinct和) |% X1 E+ o% [! }( S# N
    MergeDistinct。下面分别讨论排序算法和哈希算法。' C7 Q$ h' b/ K$ |0 y
    1.排序算法( l4 C/ P, D9 q  Z0 D* U: {" g9 B
    MergeGroupBy、MergeDistinct以及Sort都需要使用排序算法。通用的<key,value
    * c: Y% S5 P9 P) B>排序器可以分为两个阶段:
    - f9 o4 |& n# O5 m* d●数据收集:在数据收集阶段,调用者将<key,value>对依次加入到排序器。如
    ) S8 F9 ]( n& T) r% r4 y, a! r果数据总量超过排序器的内存上限,需要首先将内存中的数据排好序,并存储到外
    5 x. M( T+ O* z- V  b1 I2 y2 o$ B部磁盘中。8 [2 f6 K$ ]1 O' H
    ●迭代输出:迭代第一行数据时,内存中可能有一部分未排序的数据,磁盘中也
    2 ], Q; K, O1 A; S5 i可能有几路已经排好序的数据。因此,首先将内存中的数据排好序。如果数据总量, R# p8 W* D: U  z, H6 o
    不超过排序器内存上限,那么将内存中已经排好序的数据按行迭代输出(内排% @& B. ^* w7 h  [! M$ ?
    序);否则,对内存和磁盘中的部分有序数据执行多路归并,一边归并一边将结果
    " U: X/ Z1 c$ K5 e% J, [迭代输出。
    / \7 R1 F0 o1 Y! q, [2 ]2.哈希算法
    * p+ i- P+ a, U7 s% X" M& x* F( cHashGroupBy以及HashDistinct都需要使用哈希算法。假设需要对<key,value>对
    ) D& l7 o* h( I1 z& p. i按照key分组,那么首先使用key计算哈希值K,并将这个<key,value>对写入到第K个. X# Z) n9 Y0 o- \6 S
    桶中。不同的key可能对应相同的哈希桶,因此,还需要对每个哈希桶内的<+ X% d( f: U9 t2 {
    key,value>对排序,这样才能使得key相同的元组能够连续迭代出来。哈希算法的难& [/ o- H6 ?( U$ A$ k6 v
    点在于数据总量超过内存上限的处理,由于篇幅有限,请自行思考。
    . j) K$ p4 y/ V10.2.3 多表操作' T) ~" o- x1 C3 I  k7 F( w9 a
    多表相关的物理操作符主要是Join。最为常见的Join类型包括两种:内连接$ g  z/ m. @2 ]) `
    (Inner Join)和左外连接(Left Outer Join),而且基本都是等值连接。如果需要连接$ ~/ _# k! A. b: \) `9 }' g$ W" ?
    多张表,可以先连接前两张表,再将前两张表连接生成的结果(相当于一张临时
    8 f6 S9 i1 Q2 T: r3 {表)与第三张表格连接,以此类推。( L2 J  l. z8 v$ Y2 a2 d7 p0 G
    两张表实现等值连接方式主要分为两类:基于排序的算法(MergeJoin)以及基1 o/ z- s0 Y5 Z
    于哈希的算法(HashJoin)。对于MergeJoin,首先使用Sort运算符分别对输入表格预& D% d) v2 _1 ?4 W# U. A  d
    处理,使得两张输入表都在连接列上排好序,接着按顺序迭代两张输入表,合并连
    ( ?% r. a0 B0 H5 r7 l( M7 Q接列相同的行并输出;对于HashJoin,首先根据连接列计算哈希值K,并分别将两张1 E9 d4 U- H& K% t/ F
    输入表格的数据写入到第K个桶中。接着,对每个哈希桶按照连接列排序。最后,依
    4 k4 q% ?8 v* E+ s+ R( [次对每个哈希桶合并连接列相同的行并输出。
    6 X8 N0 ?9 F$ L子查询分为两种:关联子查询和非关联子查询,其中比较常用的是使用IN子句3 D$ u6 v, J8 l
    的非关联子查询。举例如下:
    ! W- ]4 m4 y5 W3 j7 T( g* w例10-3 假设有两张表格:item(商品表,包括商品号item_id,商品名2 W8 y9 Y. U7 t6 q" k7 ?: _4 ^
    item_name,分类号category_id,),category(类别表,包括分类号category_id,分$ H9 b7 O' W7 ~5 [6 x8 |) D
    类名category_name)。如果需要查询分类号出现在category表中商品,可以采用图10-
    , [/ t( z# f7 [  g' H& _* X; J4左边的IN子查询,而这个子查询将被自动转化为图10-4右边的等值连接。如果
    2 q: h* {  s6 G8 Ocategory表中的category_id列有重复,表连接之前还需要使用distinct运算符来删除重
      U# [. L% Q  i/ @* v, E复的记录。0 P2 ~$ ^( v% o9 q) w4 j
    图 10-4 IN子查询转化为等值连接3 d: f( s% Y% R" C9 }( P
    例10-4 例10-3中,如果category表只包含category_id为1~10的记录,那么,可; s; r- T, u/ b' \3 B
    以将IN子查询写成图10-5中的常量表达式。5 @1 H/ X+ b9 y6 A$ p( X7 ^
    图 10-5 IN子查询转化为常量表达式
    . ]4 M) h$ [! m) t% m转化为常量表达式后,MergeServer执行SQL计算时,可以将IN后面的常量列表. o, o4 Z6 ]$ V9 F- w
    发送给ChunkServer,ChunkServer只返回category_id在常量列表中的商品记录,而不是9 s& t  h5 _, b8 S* K- t
    将所有的记录返回给MergeServer过滤,从而减少二者之间传输的数据量。
    5 j  Z8 P: [7 `# H- c( HOceanBase多表操作做得还很粗糙,例如不支持嵌套连接(Nested Loop Join),
    # h: w; Y. Q8 Q9 S* l3 k3 [不支持非等值连接,不支持查询优化等,后续将在合适的时间对这一部分代码进行  h$ o5 @& i7 A) y
    重构。8 ]1 _6 r, b3 W8 O$ ]* ^7 Y
    10.2.4 SQL执行本地化
    * J, {, i& O$ I; _/ t3 HMergeServer包含SQL执行模块MS-SQL,ChunkServer也包含SQL执行模块CS-
    & E: N# C. t9 @7 ?7 U0 MSQL,那么,如何区分二者的功能呢?多表操作由MergeServer执行,对于单表操4 l7 }8 u  V% V: ^$ R% k
    作,OceanBase设计的基本原则是尽量支持SQL计算本地化,保持数据节点与计算节
    ) I* T( _9 p+ h6 n7 t; I; [点一致,也就是说,只要ChunkServer能够实现的操作,原则上都应该由它来完成。$ M# B' L0 x6 j1 K, G
    ●TableScan:每个ChunkServer扫描各自子表范围内的数据,由MergeServer合并
    ) ], _$ |! Y. F2 {( Q: M, ]; lChunkServer返回的部分结果。' P7 I& y9 M# i
    ●Filter:对基本表的过滤集成在TableScan操作符中,由ChunkServer完成。对分( M* n/ |" j# D& F( {
    组后的结果执行过滤(Having)集成在GroupBy操作符中,一般情况下由MergeServer
    - i( ]/ j" T7 F& I完成;但是,如果能够确定每个分组的所有数据行只属于同一个子表,比如SQL请求
    ; I  v) m& h8 z) B! Z, N只涉及一个tablet,那么,分组以及分组后的过滤操作符可以由ChunkServer完成。
    1 ~- P6 b& p- b●Projection:对基本表的投影集成在TableScan操作符中,由ChunkServer完成,
    + L3 {' z% d: }; e$ K% z对最终结果的投影由MergeServer完成。; {0 H) b7 [3 ]
    ●GroupBy:如果SQL读取的数据只在一个子表上,那么由该子表所在的3 y- f* M- }- b' Y: a
    ChunkServer完成分组操作;否则,每台ChunkServer各自完成部分数据的分组操作,! Z* v6 b1 e- J
    执行聚合运算后得到部分结果,再由MergeServer合并所有ChunkServer返回的部分结
    . ?: `. h- R+ f5 B+ A5 Q8 w( r: [/ m果,对于属于同一个分组的数据再次执行聚合运算。某些聚合运算需要做特殊处
    ; @% L8 ]- y2 K+ u5 w理,比如avg,需要转化为sum和count操作发送给ChunkServer,MergeServer合并
    % p7 z) b6 u# fChunkServer返回的部分结果后计算出最终的sum和count值,并通过sum/count得到avg8 c4 P9 T9 V0 R2 e7 u% n
    的最终结果。
    * n% L6 z4 t% z●Sort:如果SQL读取的数据只在一个子表上,那么由该子表所在的ChunkServer9 z# g4 s6 Q" Z  d+ g! s
    完成排序操作;否则,每台ChunkServer各自完成部分数据的排序,并将排好序的部
    ! X) H0 b8 h& O7 B分数据返回MergeServer,再由MergeServer执行多路归并。4 E3 X1 z# q0 O0 _
    ●Limit:Limit操作一般由MergeServer完成,但是,如果请求的数据只在一个子9 Q, S5 g9 W8 y9 N" z: N
    表上,可以由ChunkServer完成,这往往会大大减少MergeServer与ChunkServer之间传3 F0 F* t' [) c$ P* c, G4 h
    输的数据量。; H4 w3 \0 e2 {
    ●Distinct:Distinct与GroupBy类似。ChunkServer先完成部分数据的去重,再由
    ; K- ?# B2 L& p. XMergeServer进行整体去重。
    4 o! F3 m+ @# x6 s* _+ S7 ]0 _2 b例10-5 图10-2中的SQL语句为"select c1,sum(c2)from t1 where c3=10 group
    $ T1 ?" ?9 T7 cby c1 having sum(c2)>=10 order by c1 limit 0,20"。执行步骤如下:
    8 E' G1 x6 c% K* H2 Z/ Y" W4 r1)ChunkServer调用TableScan操作符,读取子表t1中的数据,该操作符还将执行
      {& A4 o# \1 c0 ^* Y6 `投影(Project)和过滤(Filter),返回的结果只包含c3=10的数据行,且每行只包含" C1 ]7 c; N4 V0 b. q
    c1、c2、c3三列。0 e, A( x5 ^. {0 }; Z  f
    2)ChunkServer调用HashGroupBy操作符(假设采用基于哈希的分组算法),按$ D- m! F4 v, d8 G! D6 t1 W
    照c1对数据分组,同时计算每个分组内c2列的总和sum(c2)。
    6 z- R* v; X$ m. F) ^- l3)每个ChunkServer将分组后的部分结果返回MergeServer,MergeServer将来自不
    & C7 \# O5 s# I同ChunkServer的c1列相同的行合并在一起,再次执行sum运算。2 X% a( z0 l* H0 g; ^
    4)MergeServer调用Filter操作符,过滤第3)步生成的最终结果,只返回. p; H6 b( K7 a
    sum(c2)>=10的行。' r1 V0 a7 G) J& e, N6 z
    5)MergeServer调用Sort操作符将结果按照c1排序。4 I, Y, b, f/ t: ]+ `; f7 q
    6)MergeServer调用Project操作符,只返回c1和sum(c2)这两列数据。; B$ w) \$ R" x7 K% w( w3 m5 P
    7)MergeServer调用Limit操作符执行分页操作,只返回前20条数据。
    + Q7 v2 U7 r) V* F. q当然,如果能够确定请求的数据全部属于同一个子表,那么,所有的物理运算" e" `: h5 j3 d5 h
    符都可以由ChunkServer执行,MergeServer只需要将ChunkServer计算得到的结果转发$ o9 c7 m) f, S& T9 D0 B
    给客户端。" a5 ^& p3 F2 [, N

    / \9 G1 d& c3 J* B% N3 p3 |' \+ k. C7 t1 B' B' L4 I- a# _+ a
    回复

    使用道具 举报

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

    本版积分规则

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

    GMT+8, 2024-11-21 20:37 , Processed in 0.274839 second(s), 33 queries .

    Powered by Javazx

    Copyright © 2012-2022, Javazx Cloud.

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