查询计划

查询计划是为了得到一个查询的结果所需的数据库操作集合,操作可以是scan,aggregation,join等,这些操作形成一棵树状结构,树的每一个节点是一个操作。在查询计划执行过程中,子节点的输出以流水线的形式传递到父节点。

除了常见的数据库操作外(比如scan,join等),为了支持查询的并行执行,OushuDB添加了motion操作。motion操作主要实现查询执行过程中元组在节点之间的传递。OushuDB现在支持三种motion操作:

  • redistribute motion: 按照hash值把数据发送到多个目标节点。
  • broadcast motion: 把数据广播到所有目标节点。
  • gather: 把数据从多个节点收集到一个节点。

查询计划例子

下面给出一个查询计划的例子,本例中涉及两张表,lineitem和orders。其中lineitem表较大,orders表较小。lineitem表按照l_orderkey hash分布,而orders表随机分布。

1
2
3
4
SELECT l_orderkey, count(l_quantity)
FROM lineitem, orders
WHERE l_orderkey = o_orderkey
GROUP BY l_orderkey;

上面SQL语句会产生如下图所示的查询计划。查询计划的执行是自底向上的。该查询计划表示先对orders表按照o_orderkey重新分布,然后和表lineitem做hash join,然后再做aggregation,最后结果会通过gather motion收集起来。

_images/hawk++3_2_1.png

图1. 查询计划

下面是explain的输出,和上图一样,只是不同的表示形式。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
                                               QUERY PLAN
-------------------------------------------------------------------------------------------------------------------
 Gather Motion 2:1  (slice2; segments: 2)  (cost=291565.56..318376.51 rows=1220947 width=16)
   ->  HashAggregate  (cost=291565.56..318376.51 rows=610474 width=16)
         Group By: lineitem.l_orderkey
         ->  Hash Join  (cost=70069.00..250010.38 rows=3000608 width=15)
               Hash Cond: lineitem.l_orderkey = orders.o_orderkey
               ->  Append-only Scan on lineitem  (cost=0.00..89923.15 rows=3000608 width=15)
               ->  Hash  (cost=51319.00..51319.00 rows=750000 width=8)
                     ->  Redistribute Motion 2:2  (slice1; segments: 2)  (cost=0.00..51319.00 rows=750000 width=8)
                           Hash Key: orders.o_orderkey
                           ->  Append-only Scan on orders  (cost=0.00..21319.00 rows=750000 width=8)

针对每一个操作,explain语句都会输出几方面信息:

  • cost: cost为1.0表示等价于一个顺序磁盘页读的代价。第一个cost值为start-up代价,指的是从该操作开始执行到输出第一行的代价估计值。第二个cost值为得到所有行的代价估计值。
  • rows:该计划节点估计输出行数,此处的行数估计是每一个virtual segment输出行数的估计值。
  • width:该计划节点输出元组的近似宽度。

针对某些类别节点,explain语句还会输出其他信息,比如HashAggregate的聚集key等。