概述
当查询语句中包含连接操作时,执行过程中可能产生较大的中间结果集。为此,Oceanbase中定义了外连接limit下推规则,能够将满足条件的外连接查询中的limit表达式下推至外表视图,提升查询性能。
基本原理
考虑如下情况:
SELECT * FROM t1 LEFT JOIN t2 on t1.c1 = t2.c1 ORDER BY t1.c2 LIMIT 10
对于上述查询,其中的order by和limit表达式只涉及外表,因而可以进行下推改写,如下所示:
SELECT * FROM (SELECT * FROM t1 ORDER BY t1.c2 LIMIT 10) v LEFT JOIN t2 on v.c1 = t2.c1
代码解析
外连接limit下推规则的入口为ObTransformAggregate::transform_one_stmt,执行流程如下:
调用check_stmt_validity函数检查查询语句是否能够被改写。
调用do_transform函数执行改写。
check_stmt_validity函数首先会调用check_basic函数对查询语句的基本属性进行检查,能够被改写的语句需要满足如下条件:
查询语句中不包含distinct、group by表达式、having条件和窗口函数,不涉及半连接。
查询语句中包含limit表达式。
查询语句的from表中仅包含一张join表,且该表的类型为必须为左深树(右深树会被转换为左深树)。左深树的左叶子节点为视图表时,查询语句的where条件为空。
对于满足上述条件的查询,该函数会调用check_orderby_and_condition函数收集查询语句中的where条件和order by表达式,然后判断语句中是否存在满足条件的目标外表,执行流程如下:
调用collect_condition_exprs_table_ids函数收集查询语句中的where条件及涉及的表id。
调用collect_orderby_table_ids函数收集查询语句中的order by表达式及涉及的表id。
调用find_target_table函数从join表中找到下推的目标表,该函数会从根节点开始遍历左深树中的左节点。对于每一个树节点,如果其包含的子节点的表id集合与前两步得到的表id的并集相同,说明该节点的左右节点都被包含在where条件或order by表达式中,因此选择该节点作为目标节点。如果根节点满足要求,则说明无法进行下推,因此会退出改写流程。
调用check_validity_for_target_table函数判断目标节点能够被改写,以及是否需要为其创建视图。如果目标节点为基表或join表,则可以进行改写,且需要创建视图;如果目标节点为视图表,则需要根据如下条件进行进一步判断:
视图查询中包含order by表达式、limit表达式或者窗口函数时,不能进行改写。
视图查询为集合语句时,能够进行改写,但需要额外创建视图。
其他情况,能够进行改写且不需要额外创建视图。
do_transform函数负责执行下推改写,处理流程如下:
调用remove_and_copy_condition_orderby函数从父查询中移除需要下推的where条件,同时获取拷贝需要下推的order by条件。
调用ObTransformUtils::create_view_with_table函数为目标节点创建视图。
调用pushdown_view_table函数将where条件、order by表达式和limit表达式下推到视图表中。
调用add_condition_expr_for_viewtable函数将where条件下推到视图表中。如果目标表为视图表,则需要更新下推表达式的列依赖。
调用add_orderby_for_viewtable函数将order by表达式下推到视图表中。如果目标表为视图表,则需要更新下推表达式的列依赖。
调用add_limit_for_viewtable函数将limit表达式下推到视图表中。