Oceanbase查询改写:groupby移动
概述
当查询语句中同时存在连接操作和分组聚合操作时,可能会产生大量的io。为此,Oceanbase中定义了groupby移动规则,能够对满足条件的分组聚合操作进行提升或下推,提升查询性能。
基本原理
groupby移动规则主要包含对以下两种情况的处理:
- groupby下推:当分组聚合操作位于连接操作之后时,可以将其进行下推,从而通过提前聚合减少连接阶段的数据量。
- groupby提升:当分组聚合操作位于连接操作之前时,可以将其进行提升,从而通过连接筛选减少分组聚合阶段的数据量。
groupby下推
考虑如下情况:
SELECT sum(t1.c2) FROM t1, t2 WHERE t1.c1 = t2.c1 GROUP BY t1.c3;
对于上述查询,可以将通过改写将group by表达式下推,从而减少连接阶段的数据量,如下所示:
SELECT sum(c2_sum * t2_cnt) FROM
(SELECT t1.c1, t1.c3, sum(t1.c2) AS c2_sum FROM t1 GROUP BY t1.c1, t1.c3) v1,
(SELECT t2.c1, count(*) AS t2_cnt FROM t2 GROUP BY t2.c1) v2
WHERE v1.c1 = v2.c1 GROUP BY v1.c3
groupby提升
SELECT t1.c3, c2_sum FROM
t1,
(SELECT t2.c3, sum(t2.c2) AS c2_sum FROM t2 GROUP BY t2.c3) v
WHERE v.c3 = t1.c3
对于上述查询,如果连接操作能够筛选掉较多的数据,则可以通过改写提升group by表达式,从而减少参与聚合的数据量,如下所示:
SELECT t1.c3, sum(t2.c2) AS c2_sum FROM
t1,
t2
WHERE t2.c3 = t1.c3 GROUP BY t2.c3, t1.c1 --c1为t1表的唯一键
代码解析
groupby移动规则的入口为ObTransformGroupByPlacement::transform_one_stmt,执行流程如下:
- 调用transform_groupby_push_down函数执行groupby下推改写。
- 调用transform_groupby_pull_up函数执行groupby提升改写。
groupby下推
transform_groupby_push_down函数执行流程如下:
- 调用check_groupby_push_down_validity函数判断当前语句是否能够被执行下推改写。
- 调用compute_push_down_param函数收集下推参数。
- 调用do_groupby_push_down函数执行下推改写。
check_groupby_push_down_validity函数会对查询语句的各项成员进行检查,执行流程如下:
- 检查查询语句的基本属性是否满足如下条件:
- 查询语句必须包含聚合函数和group by表达式,且不包含窗口函数、半连接信息和子查询。
- 查询语句不是集合语句。
- 调用check_groupby_validity函数检查查询语句的select列、order by表达式及having表达式是否都包含于group by表达式。
- 调用check_collation_validity函数检查查询语句中数据类型为string或者lob的列对应的collation类型是否一致。
- 检查聚合函数类型是否都属于min/max/count/sum中的一种,且不含distinct参数。
compute_push_down_param函数负责收集下推参数,判断应该如何将查询语句中涉及的表划分到不同的视图中。该函数首先会为表信息中的每张表分配一个表集合,然后将满足条件的集合进行合并,执行逻辑如下:
- 遍历查询语句中的聚合项,如果某个聚合函数的参数涉及多张表,则将这些表合并到同一视图中。
- 遍历查询语句中的where条件,将满足如下条件的表达式涉及的表合并到同一视图中:
- 该表达式为两表连接条件(涉及两表的关系比较条件)。
- 左右参数中任意一侧的列表达式涉及的表与聚合项涉及的表存在重叠,且该列能够找到匹配的索引。
- 遍历查询语句中的join表,将满足如下条件之一的join表涉及的表合并到同一视图中:
- 与该join表存在交集的集合中已经至少分配了两张表。
- 查询语句中的聚合项中存在某个聚合函数的参数涉及该join表的内表侧数据表,且该参数关于对应的数据列不满足空值传递(此时无法找到等价的语义进行拆分)。