java自学网VIP

Java自学网

 找回密码
 立即注册

QQ登录

只需一步,快速开始

查看: 2516|回复: 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 只读事务( t6 O, u9 _" z3 ?, }5 G8 L, X# j2 O
    只读事务(SELECT语句),经过词法分析、语法分析,预处理后,转化为逻辑: m3 |3 `1 {' l: k( ^
    查询计划和物理查询计划。以SQL语句select c1,c2 from t1 where id=1 group by c1& E) o& u# |: z' l
    order by c2为例,MergeServer收到该语句后将调用ObSql类的静态方法  `' m) V$ u0 S9 [% w( I
    direct_execute,执行步骤如下:
    + `, h" M4 X7 T! E) y5 H! U1)调用flex、bison解析SQL语句生成一个语法树。
    & {6 W9 B3 l8 h7 |$ t2)解析语法树,生成逻辑执行计划ObSelectStmt。ObSelectStmt结构中记录了
    " r0 Y* f/ u: y- m+ Y) V! rSQL语句扫描的表格名(t1),投影列(c1,c2),过滤条件(id=1),分组列2 c$ |7 _3 V. ~9 d8 c6 T
    (c1)以及排序列(c2)。
    ; y% n+ m( ?( |4 a* F! a3)根据逻辑执行计划生成物理执行计划。ObSelectStmt只是表达了一种意图," {# I! \7 K. Y: Z3 I6 i! Y; `+ f
    但并不知道实际如何执行,ObTransformer类的generate_physical_plan将ObSelectStmt转
    7 g8 n( \% x+ Q! X3 ^$ i0 ~化为物理执行计划。; _3 U2 }1 Q) x4 o( n  W. c9 q
    逻辑查询计划的改进以及物理查询计划的选择,即查询优化器,是关系数据库
    5 I4 ^% v- @! u( F最难的部分,OceanBase目前在这一部分的工作不多。因此,本节不会涉及太多关于
    2 d1 H: ^, m: o" R' w如何生成物理查询计划的内容,下面仅以两个例子说明OceanBase的物理查询计划。
    2 j1 ?  v" a5 h) }) n例10-1 假设有一个单表SQL语句如图10-2所示。. N' z. N3 ?# ]7 B, |% f
    图 10-2 单表物理查询计划示例- T& Z1 y" ~1 Y, Y1 Y: A
    单表SQL语句执行过程如下:
    $ C6 A5 D) c- m/ b( }6 ?* v1)调用TableScan操作符,读取子表t1中的数据,该操作符还将执行投影
    3 W( B% q" S4 w4 w/ e& t. I(Project)和过滤(Filter),返回的结果只包含c3=10的数据行,且每行只包含c1、# Z: K: Y. i2 g3 m! o
    c2、c3三列。" v% ?# [5 e! ~6 j
    2)调用HashGroupBy操作符(假设采用基于哈希的分组算法),按照c1对数据2 B4 ?2 M' j# C! ]# b
    分组,同时计算每个分组内c2列的总和。0 T  ]# \4 ^; X
    3)调用Filter操作符,过滤分组后生成的结果,只返回上一层sum(c2)>=10的
    ( q0 ]* c& Y: r: j4 o行。4 D3 I4 O9 D; g/ C/ G
    4)调用Sort操作符将结果按照c1排序。/ ?2 e* W1 a* N/ [" B
    5)调用Project操作符,只返回c1和sum(c2)这两列数据。& f) X# S2 D4 F: z" B0 B* F
    6)调用Limit操作符执行分页操作,只返回前20条数据。, U9 [/ q6 A/ |2 j. ^/ w% s  {
    例10-2 假设有一个需要联表的SQL语句如图10-3所示。
    1 D2 W1 P9 T: N4 Y) l+ r3 j* T图 10-3 多表物理查询计划示例8 m& p5 U' F! q" L2 Z$ z
    多表SQL语句执行过程如下:' c2 Z; a, ?$ R  P7 F
    1)调用TableScan分别读取t1和t2的数据。对于t1,使用条件c3=10对结果进行过4 j. H8 U+ r0 c0 v
    滤,t1和t2都只需要返回c1,c2,c3这三列数据。% f, q- s3 F+ O, ?  S" W
    2)假设采用基于排序的表连接算法,t1和t2分别按照t1.c2和t2.c2排序后,调用
    ; T: k2 i2 m, T) j9 v, zMerge Join运算符,以t1.c2=t2.c2为条件执行等值连接。+ r* C; L! Z: f, b
    3)调用HashGroupBy运算符(假设采用基于哈希的分组算法),按照t1.c1对数
    0 ^2 S3 E5 |* @) m, E0 W  z2 g据分组,同时计算每个分组内t2.c3列的总和。
    2 j# ]( y3 O1 g; O4)调用Filter运算符,过滤分组后的生成的结果,只返回上一层sum(t2.c3)>0 B7 c/ h# E8 E; j& @4 }
    =10的行。
    1 z9 K6 w( c; H+ {( ^4 \5)调用Sort操作符将结果按照t1.c1排序。
    8 W/ A7 u& T1 a% l6)调用Project操作符,只返回t1.c1和sum(t2.c3)这两列数据。& @! d1 C; x9 j! P- e. w$ j& T
    7)调用Limit操作符执行分页操作,只返回前20条数据。
    3 k7 h( W  O. A- [" K& [10.2.1 物理操作符接口* {* n. \3 o' L
    9.4.2节介绍一期分布式存储引擎中的迭代器接口为ObIterator,通过它,可以将
    % m8 l0 {8 `9 H/ b5 L! ^0 Q读到的数据以cell为单位逐个迭代出来。然而,数据库操作总是以行为单位的,因/ }, p7 O" t. u0 m6 C$ P$ R
    此,二期实现数据库功能层时考虑将基于cell的迭代器修改为基于行的迭代器。3 n$ w# {( X! K9 E
    行迭代器接口如下:
    2 c2 D/ c( ^4 O+ h9 E1 m//ObRow表示一行数据内容2 d. b6 t3 Y& _8 q; D) t
    class ObRow: C$ f8 m4 |5 c9 f& C
    {
    # J8 j% n, G- G0 }4 Q. d  J8 N) Npublic:$ w3 u! M6 L1 q" v! H& F
    //根据表ID以及列ID获得指定cell1 w$ _4 Z8 A+ Z9 ?, X& i& v7 c. z$ d
    //@param[in]table_id表格ID3 C2 Q, N4 }: q
    //@param[in]column_id列ID
      [  s8 A4 M3 }- n//@param[out]cell读到的cell
    3 X9 b: K5 X" G$ Z( {$ J+ g( Cint get_cell(const uint64_t table_id,const uint64_t column_id,ObObj*&cell);; L+ h; Z  Q# X  k) u
    //获取第cell_idx个cell7 k+ \7 ]3 `, Z5 ^
    int raw_get_cell(const int64_t cell_idx,const ObObj*&cell,uint64_t&table_id,
    - E% `, y- K1 G9 luint64_t&column_id);! T- _. R* ^) y4 U' i
    //获取本行的列数
    + _  i. x: C: T" H! r' @int64_t get_column_num()const;
      O& |' Z* d* s0 x! }+ Z};
    ! a! g$ ]; W' [9 r' F# D每一行数据(ObRow)包括多个列,每个列的内容包括所在的表
    7 [; \) H; E6 h( AID(table_id),列ID(column_id)以及列内容(cell)。ObRow提供两种访问方
    1 `' Z* B, q4 t式:根据table_id和column_id随机访问某个列,以及根据列下标(cell_idx)获取某个
    $ r3 o, p- G* b$ S) Z( F指定列。
    ! L; y1 v% e; [9 M. Y  N* K' k物理运算符接口如下:" W, U! q; M. F0 R* g8 Y
    //物理运算符接口
    * `4 D% B" d( c5 E# `5 d( Nclass ObPhyOperator5 Y* o( A+ w. q" y
    {
    2 l& f0 C* R  B0 O+ ?& a- p- jpublic:( h3 ?# B- S" C8 S1 K. f# b. c
    //添加子运算符,所有非叶子节点物理运算符都需要调用该接口
    * L5 j6 [( X0 `; y( F$ E% i5 J$ tvirtual int set_child(int32_t child_idx,ObPhyOperator&child_operator);
    4 z" s5 g+ h: z! {8 v//打开物理运算符。申请资源,打开子运算符等
    5 I* N  H& g4 e, H- Dvirtual int open()=0;( ?' ]* C& D& M% W/ f
    //关闭物理运算符。释放资源,关闭子运算符等
    # P8 i( v$ e# [6 C" ]" dvirtual int close()=0;
    6 @2 ?. }) L) o5 L7 `//获得下一行数据内容+ V9 C* E- m  ]
    //@param[out]row下一行数据内容的引用# s* Z! ?5 |/ y- Z3 l( e% }
    //@return返回码,包括成功、迭代过程中出现错误以及迭代完成
    3 {+ }; }( S0 Ovirtual int get_next_row(const ObRow*&row)=0;
    4 h* T/ \6 w+ R# ?/ s};
      ?: i1 J7 x( I" L4 M6 fObPhyOperator每次获取一行数据,使用方法如下:
    $ I8 j! v4 w% s! O5 w7 i4 L) J  z4 A1 NObPhyOperator root_operator=root_operator_;//根运算符
    5 w$ @  b* e4 C* y5 proot_operator->open();
    # w2 x# @! x" x' I- `* P3 MObRow*row=NULL;
    ; f" }% M/ W2 R! x; r# a- awhile(OB_SUCCESS==root_operator->get_next_row(row))6 u( }: i. H$ J) t
    {
    5 Y5 X8 ]' a. o9 _- E. h6 WOutput(row);//输出本行
    # Z2 }2 G/ c, X) ?$ G0 p}
    - y8 B% ~3 t6 n7 s. V5 _root_operator->close();
    / x) t% @( H5 P. Z为什么ObPhyOperator类中有一个set_child接口呢?这是因为所有的物理运算符构
    / T2 X7 \; [9 r" Z1 E7 U: q成一个树,每个物理运算的输出结果都可以认为是一个临时的二维表,树中孩子节
    0 R# W2 D6 p* e  X: W8 t点的输出总是作为它的父亲节点的输入。例10-1中,叶子节点为一个TableScan类型
    % g2 @. m& |  ]% D) c的物理运算符(称为table_scan_op),它的父亲节点为一个HashGroupBy类型的物理5 |" D( ~! T; Q' P
    运算符(称为hash_group_by_op),接下来依次为Filter类型物理运算符filter_op,Sort
    6 O6 M+ W, }: G6 {6 l( V类型物理运算符sort_op,Project类型物理运算符project_op,Limit类型物理运算符
    " y; \6 Y/ l- h6 Ulimit_op。其中,limit_op为根运算符。那么,生成物理运算符时将执行如下语句:
    , B- b7 E# T- v" Wlimit_op->set_child(0,project_op);; B( L* F  V3 s
    project_op->set_child(0,sort_op);( U: G' j- i6 q' v/ W" D7 w
    sort_op->set_child(0,filter_op);. q5 l: M, K3 `& A7 ?
    filter_op->set_child(0,hash_group_by_op);# ~) j$ s8 ]; N* z2 i& X/ e( L1 T" z
    hash_group_by_op->set_child(0,table_scan_op);1 o" D) V# P9 L6 l8 F
    root_op=limit_op;
    ) ~  C- V. b# u' P# LSQL最终执行时,只需要迭代root_op(即limit_op)就能够把需要的数据依次迭0 I6 k8 K' F% m8 S
    代出来。limit_op发现前一批数据迭代完成则驱动下层的project_op获取下一批数据,5 E9 T5 Q, v. k, X: M
    project_op发现前一批数据迭代完成则驱动下层的sort_op获取下一批数据。以此类
    $ Q8 _5 ?0 f. L推,直到最底层的table_scan_op不断地从原始表t1中读取数据。
    9 I2 i- m% D" G+ O10.2.2 单表操作" m5 B+ a, _# q0 F4 F
    单表相关的物理运算符包括:- L2 {) @1 ?: W
    ●TableScan:扫描某个表格,MergeServer将扫描请求发给请求的各个子表所在
    ; h% q/ c* r+ Z7 ]: V的ChunkServer,并将ChunkServer返回的结果按照子表范围拼接起来作为输出。如果) x* I- j1 G* j
    请求涉及多个子表,TabletScan可由多台ChunkServer并发执行。* o+ |' n( M3 P2 b: B/ }4 h
    ●Filter:针对每行数据,判断是否满足过滤条件。
    5 h3 J! z* }4 ~# J9 p$ }+ [●Projection:对输入的每一行,根据定义的输出表达式,计算输出结果行。
    # d: b1 {; r7 D' m2 W●GroupBy:把输入数据按照指定列进行聚集,对聚集后的每组数据可以执行计
    0 @* F  Q  P- J( T6 ?数(count)、求和(sum)、计算最小值(min)、计算最大值(max)、计算平均值
    2 Q  `  p! Q) j& |0 ~' _(avg)等聚集操作。, Z% w) X6 W/ t9 ^7 R, H8 |  R
    ●Sort:对输入数据进行整体排序,如果内存不够,需要使用外排序。- _, Q, G$ }6 H9 Q/ |" o: J8 u
    ●Limit(offset,count):返回行号在[offset,offset+count)范围内的行。
    " c6 f; U. m7 W8 l: P+ Q●Distinct:消除某些列相同的重复行。
    . F/ ?, t( G9 _GroupBy、Distinct物理操作符可以通过基于排序的算法实现,也可以通过基于哈
    # P! P4 B/ X+ Q4 ~* b2 w希的算法实现,分别对应HashGroupBy和MergeGroupBy,以及HashDistinct和
    . S) F5 Y& u+ j8 e4 ]$ b- [MergeDistinct。下面分别讨论排序算法和哈希算法。' g4 f2 q% Q- }
    1.排序算法
    - T1 o: r1 X% Y3 EMergeGroupBy、MergeDistinct以及Sort都需要使用排序算法。通用的<key,value
    # o+ `' P* Y) B8 F>排序器可以分为两个阶段:0 A6 p( m$ P" `7 M  K
    ●数据收集:在数据收集阶段,调用者将<key,value>对依次加入到排序器。如
    9 d1 d- y2 @6 U# [* r1 a$ l( r, t果数据总量超过排序器的内存上限,需要首先将内存中的数据排好序,并存储到外0 H# x$ E, f" [! K8 m* U4 U8 h8 J
    部磁盘中。, q" L2 `% y. ]( m; B6 u! c) w. ^
    ●迭代输出:迭代第一行数据时,内存中可能有一部分未排序的数据,磁盘中也
    " f+ f3 _! u4 u- V, S" d9 k& Q8 L可能有几路已经排好序的数据。因此,首先将内存中的数据排好序。如果数据总量
    " }6 W$ C! f8 x不超过排序器内存上限,那么将内存中已经排好序的数据按行迭代输出(内排
    ' y: a7 m/ v3 `. V5 }- O) h9 a$ I序);否则,对内存和磁盘中的部分有序数据执行多路归并,一边归并一边将结果
    , D! k* U, g# ~( B6 K& m迭代输出。2 d2 U  [1 o- G0 F* z# F" R% c
    2.哈希算法/ X/ W/ M( O2 d0 h0 h7 O, {
    HashGroupBy以及HashDistinct都需要使用哈希算法。假设需要对<key,value>对" ~: I  u2 X1 Z  v
    按照key分组,那么首先使用key计算哈希值K,并将这个<key,value>对写入到第K个& M6 X# Q8 j. p2 o
    桶中。不同的key可能对应相同的哈希桶,因此,还需要对每个哈希桶内的<8 s$ W0 O' r1 N+ G* [
    key,value>对排序,这样才能使得key相同的元组能够连续迭代出来。哈希算法的难
    ' Y- j5 V% D  q点在于数据总量超过内存上限的处理,由于篇幅有限,请自行思考。% j# i" [) Z$ ~$ |4 u
    10.2.3 多表操作
    . w  @. ^- z+ Q5 y$ O9 Y多表相关的物理操作符主要是Join。最为常见的Join类型包括两种:内连接
    1 [! c, z+ X4 }(Inner Join)和左外连接(Left Outer Join),而且基本都是等值连接。如果需要连接
    4 n) ?5 c3 m7 A/ ]5 F3 e! I多张表,可以先连接前两张表,再将前两张表连接生成的结果(相当于一张临时6 [# ]+ a6 \; l  J% W* a
    表)与第三张表格连接,以此类推。
    & K, n) U0 ^' R+ U两张表实现等值连接方式主要分为两类:基于排序的算法(MergeJoin)以及基$ o( `" Y" O6 ]5 y  Y1 e
    于哈希的算法(HashJoin)。对于MergeJoin,首先使用Sort运算符分别对输入表格预9 h: J: q4 ?  i; y5 ^2 a& y
    处理,使得两张输入表都在连接列上排好序,接着按顺序迭代两张输入表,合并连
    # v' q' l  L5 z1 i( e, p接列相同的行并输出;对于HashJoin,首先根据连接列计算哈希值K,并分别将两张
    8 w/ D/ f% ]; h输入表格的数据写入到第K个桶中。接着,对每个哈希桶按照连接列排序。最后,依
    5 u: F3 V; n& f) }0 F次对每个哈希桶合并连接列相同的行并输出。9 J/ o' e5 O- Q4 X# [/ r2 F/ i* T) Z
    子查询分为两种:关联子查询和非关联子查询,其中比较常用的是使用IN子句
    # Y( I5 j2 H( v% |3 h  }的非关联子查询。举例如下:, w  u. U# c+ T! T0 U- ~& f
    例10-3 假设有两张表格:item(商品表,包括商品号item_id,商品名
    * s" f( J0 R$ D) E. U5 t" qitem_name,分类号category_id,),category(类别表,包括分类号category_id,分, q# L- c6 X' I( R$ v3 c, V& O) y; r
    类名category_name)。如果需要查询分类号出现在category表中商品,可以采用图10-
    : C* q- I7 ^/ I4左边的IN子查询,而这个子查询将被自动转化为图10-4右边的等值连接。如果
    " v5 e# S: U4 P8 H: i$ mcategory表中的category_id列有重复,表连接之前还需要使用distinct运算符来删除重4 \3 C1 p2 t4 y$ F" Q- R/ @
    复的记录。
    # ~- n4 ~% l: e6 x7 E* ^图 10-4 IN子查询转化为等值连接
    6 `$ S* K/ O1 `; N* S- o例10-4 例10-3中,如果category表只包含category_id为1~10的记录,那么,可- [$ d5 V. B+ _# _* F
    以将IN子查询写成图10-5中的常量表达式。
    , x- ~2 c& i. l* @图 10-5 IN子查询转化为常量表达式
    : I9 T" ^+ n; C: K" l4 g转化为常量表达式后,MergeServer执行SQL计算时,可以将IN后面的常量列表5 `* F3 k4 v" J: D
    发送给ChunkServer,ChunkServer只返回category_id在常量列表中的商品记录,而不是- G% q: _* w" L& z4 {
    将所有的记录返回给MergeServer过滤,从而减少二者之间传输的数据量。
    . [  U3 S) g9 h7 V3 E5 F/ i/ i$ VOceanBase多表操作做得还很粗糙,例如不支持嵌套连接(Nested Loop Join),7 _/ b' U4 o, P( M3 s0 a. {
    不支持非等值连接,不支持查询优化等,后续将在合适的时间对这一部分代码进行7 m4 k3 m  s* m. l* g7 z: m
    重构。
    , V; ]0 Y& l0 u8 j8 o. z( W5 w10.2.4 SQL执行本地化5 T% g5 v+ \2 Y4 c4 h7 b! c
    MergeServer包含SQL执行模块MS-SQL,ChunkServer也包含SQL执行模块CS-' o% u1 B% X( f) ], L, c4 K
    SQL,那么,如何区分二者的功能呢?多表操作由MergeServer执行,对于单表操6 F& f! Y) r0 V
    作,OceanBase设计的基本原则是尽量支持SQL计算本地化,保持数据节点与计算节
    / G7 N  c( `) |. W' b6 W6 R  [点一致,也就是说,只要ChunkServer能够实现的操作,原则上都应该由它来完成。) s* w/ f5 o# r; g
    ●TableScan:每个ChunkServer扫描各自子表范围内的数据,由MergeServer合并
    - `  s1 a& Y/ ^7 P$ V9 J1 FChunkServer返回的部分结果。
    8 I  O, n& q4 |0 n9 m●Filter:对基本表的过滤集成在TableScan操作符中,由ChunkServer完成。对分
    ! f/ |& O% B; C# A0 t组后的结果执行过滤(Having)集成在GroupBy操作符中,一般情况下由MergeServer' _6 R3 N! i% Q' Y
    完成;但是,如果能够确定每个分组的所有数据行只属于同一个子表,比如SQL请求9 j0 ]3 C% k7 N
    只涉及一个tablet,那么,分组以及分组后的过滤操作符可以由ChunkServer完成。
    8 S* w4 x: l' j/ d! K' k: [8 H●Projection:对基本表的投影集成在TableScan操作符中,由ChunkServer完成,
    $ `( ?, n4 \% x& S, \. O1 G对最终结果的投影由MergeServer完成。
    # p* t7 N$ W- i% ~2 I3 @0 k2 s●GroupBy:如果SQL读取的数据只在一个子表上,那么由该子表所在的
    $ z9 y) y( z2 aChunkServer完成分组操作;否则,每台ChunkServer各自完成部分数据的分组操作,
    2 h+ G" z% M" J8 ?1 s7 p6 }, f执行聚合运算后得到部分结果,再由MergeServer合并所有ChunkServer返回的部分结
    4 \* y# t+ O' e0 }# a- Q果,对于属于同一个分组的数据再次执行聚合运算。某些聚合运算需要做特殊处2 T2 Q$ J! Y) \5 b/ S) _
    理,比如avg,需要转化为sum和count操作发送给ChunkServer,MergeServer合并
    : U/ ]$ b  H* P, {+ U- C- BChunkServer返回的部分结果后计算出最终的sum和count值,并通过sum/count得到avg. L2 u" o9 M+ R
    的最终结果。! @5 S, h+ {! ^# o
    ●Sort:如果SQL读取的数据只在一个子表上,那么由该子表所在的ChunkServer( W( Q) F: i, N* w. j4 F
    完成排序操作;否则,每台ChunkServer各自完成部分数据的排序,并将排好序的部
    $ b; M1 c' j. c$ q7 }分数据返回MergeServer,再由MergeServer执行多路归并。* a# m' I  U3 d+ X3 s8 I  y
    ●Limit:Limit操作一般由MergeServer完成,但是,如果请求的数据只在一个子
    + e2 v* y  w9 d# ?9 i" [表上,可以由ChunkServer完成,这往往会大大减少MergeServer与ChunkServer之间传
    - I" J% @% u( ^# |  K输的数据量。: b" |( A3 A; ?8 E# X, i1 Q+ C" C
    ●Distinct:Distinct与GroupBy类似。ChunkServer先完成部分数据的去重,再由
    9 m% ]8 s7 {7 x9 bMergeServer进行整体去重。2 k2 b+ U& e8 J# ?" A" }8 u  D
    例10-5 图10-2中的SQL语句为"select c1,sum(c2)from t1 where c3=10 group! L) F0 }8 n% ^& E
    by c1 having sum(c2)>=10 order by c1 limit 0,20"。执行步骤如下:
    ) J/ L9 y- R* ^. v/ J1)ChunkServer调用TableScan操作符,读取子表t1中的数据,该操作符还将执行: V) s  f8 p# f6 o9 Y
    投影(Project)和过滤(Filter),返回的结果只包含c3=10的数据行,且每行只包含1 ?3 W) d% U3 l9 p- R
    c1、c2、c3三列。
    % W) v' n" ?! D/ @7 H( i& ~2)ChunkServer调用HashGroupBy操作符(假设采用基于哈希的分组算法),按
    6 G" q7 X+ \$ c7 }" _5 |" d; d8 b照c1对数据分组,同时计算每个分组内c2列的总和sum(c2)。
    ; V( {3 ^$ Z" L3)每个ChunkServer将分组后的部分结果返回MergeServer,MergeServer将来自不
    8 i0 G5 E2 a  v; O1 o: G: g' i! P# ^同ChunkServer的c1列相同的行合并在一起,再次执行sum运算。
    ' D5 T+ J) T- e2 ]( T0 N4)MergeServer调用Filter操作符,过滤第3)步生成的最终结果,只返回$ F& X9 R, S5 S/ Y
    sum(c2)>=10的行。
    + X5 n! P3 T! S, i8 q5)MergeServer调用Sort操作符将结果按照c1排序。
    9 \  v: m1 O5 ]4 H$ }" I6)MergeServer调用Project操作符,只返回c1和sum(c2)这两列数据。
    & c7 V( L/ a' M, h* e& Q7)MergeServer调用Limit操作符执行分页操作,只返回前20条数据。, r# p* L8 I6 k. C3 \5 S+ y
    当然,如果能够确定请求的数据全部属于同一个子表,那么,所有的物理运算
    ; I" c7 z& H4 m6 B8 S5 {符都可以由ChunkServer执行,MergeServer只需要将ChunkServer计算得到的结果转发4 A9 u* E2 Q: O
    给客户端。) J" @& L7 x  c5 Y, G4 V- c
    2 d$ U& `. ^/ ?; p& ]

    % s# _8 z1 n: A
    回复

    使用道具 举报

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

    本版积分规则

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

    GMT+8, 2025-4-1 14:14 , Processed in 0.296967 second(s), 31 queries .

    Powered by Javazx

    Copyright © 2012-2022, Javazx Cloud.

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