系列文章导读一、 引言 优化谓词推导提升查询性能是至关重要的。谓词可以出现在一个 SQL 的多个位置上,可以是主查询的 Where/Having 子句;也可以是子查询的 Where/Having 子句。上一篇文章《SQL 改写系列六:谓词推导》介绍了谓词推导只能对每个字句进行独立优化;无法对它们进行综合优化。本文将重点介绍谓词移动技术,它可以改进一个谓词在 SQL 中出现的位置,也可以综合多个位置上的谓词进行推导优化。
OceanBase 是100% 自主研发,连续9年稳定支撑双11,创新推出“三地五中心”城市级容灾新标准,是全球唯一在 TPC-C 和 TPC-H 测试上都刷新了世界纪录的国产原生分布式数据库,于 2021 年 6 月份正式开放源代码。查询优化器是关系数据库系统的核心模块,是数据库内核开发的重点和难点,也是衡量整个数据库系统成熟度的“试金石”。为了帮助大家更好地理解 OceanBase 查询优化器,我们将撰写查询改写系列文章,带大家更好地掌握查询改写的精髓,熟悉复杂 SQL 的等价性,写出高效的 SQL。本文是 OceanBase 改写系列第七篇,将重点和大家介绍一下谓词移动的技术,欢迎探讨~
专栏作者介绍
OceanBase 优化器团队,由 OceanBase 高级技术专家溪峰、技术专家山文等领衔,致力于打造全球领先的分布式查询优化器。
系列内容构成
本次查询改写系列不仅包括子查询优化、聚合函数优化、 窗口函数优化、 复杂表达式优化四大模块,另外还有更多模块内容,敬请期待!本文将通过介绍谓词移动的部分下推和上拉场景,来帮助读者快速理解这两个策略的概念和作用。欢迎关注 OceanBase 开源用户群 (钉钉号:33254054),进群与 OceanBase 查询优化器团队一同交流。
二、谓词下推 谓词用于过滤数据。一般来说,尽早地进行数据过滤,可以减少中间结果集的大小,减少后续计算需要处理的数据量。因此,谓词的一个重要优化点是谓词下推。这个优化策略的主要作用是,尽可能的“下压”谓词,提前过滤掉部分数据。
在这一节中,我们将以 Q1 为例,介绍谓词下推的几种场景。
?
Q1:
SELECT V1.C1, V2.C2, V1.M1, V2.M2
FROM
(SELECT C1, 0 AS C2,MAX(C3) as M1 FROM T1 GROUP BY C1) V1,
(SELECT C1,C2,AVG(C3) as M2 FROM T2 GROUP BY C1, C2 HAVING M2 > 0) V2
WHERE V1.C1 = V2.C1 AND V1.C2 = V2.C2 AND V1.M1 > V2.M2 AND V1.C1 > 10;
Q1 的 FROM 部分是两个内联视图
V1
和 V2
。Q1 主查询的 WHERE 部分有多个谓词。其中 V1.C1 > 10
是视图 V1
上的单表过滤条件。谓词下推可以将它推入到视图内部。1、谓词推入视图
显然,我们可以将 V1.C1 > 10 这个谓词移到 V1 内部。在这里,由于 V1 存在分组聚合操作,因此,从外层下推的谓词是放到 Having 子句中。
V1.C1 > 10 推入视图V1-1: SELECT C1, 0 AS C2,MAX(C3) as M1 FROM T1 GROUP BY C1 HAVING C1 > 10
经过谓词下推之后,V1 的输出保证了
C1 > 10
是必然成立的。因此,原始主查询中 V1.C1 > 10
的判定结果是恒真的,这是一个冗余的谓词,可以直接移除。2、谓词推入分组
Having 子句中的谓词还可以尝试进一步下推。可以看到,
C1 > 10
是分组列上的谓词。它在分组之前或者分组之后执行产生的效果是完全相同的。我们将其压入到 Where 子句中,可以提前过滤掉部分数据,减少 GROUP BY 操作需要处理的数据量。C1 > 10 推入 WHEREV1-2: SELECT C1, 0 AS C2, MAX(C3) AS M1 FROM T1 WHERE C1 > 10 GROUP BY C1;
当然, 并不是所有 Having 中的谓词都可以下推到 Where 中。V2 中存在一个谓词
M2 > 0
,这个谓词引用了一个聚合函数 AVG(C3)
。聚合函数的结果依赖于分组聚合计算。因此,这个谓词无法下压到分组操作之前。3、谓词下推和谓词推导
Q1 原始查询中只有 V1 和 V2 的连接谓词、以及 V1 上的谓词。但通过上一篇文章中介绍的谓词推导技术,我们可以推导出 V2 的过滤谓词:
V2.C1 > 10
。这个推导谓词同样可以压入到 V2 中,优化 V2 的计算。可以看到,谓词推导和谓词下推是相互作用的。推导可以产生更多的下推的机会。同样的,下推之后,也可以产生更多的推导机会。利用这两种优化策略,我们可以将 Q1 优化为以下查询:Q1 初步优化结果:
SELECT V1.C1, V1.C2, V1.M1, V2.M2
FROM
(SELECT C1, 0 AS C2, MAX(C3) AS M1
FROM T1
WHERE C1 > 10
GROUP BY C1) V1,
(SELECT C1, C2, AVG(C3) AS M2
FROM T2
WHERE C1 > 10
GROUP BY C1, C2 HAVING M2 > 0) V2
WHERE V1.C1 = V2.C1 AND V1.C2 = V2.C2 AND V1.M1 > V2.M2;
通过谓词推导和下推,我们对 Q1 进行了一定的优化。那以上结果是否为优化的最终答案呢?答案是否定的。接下来,我们将介绍另外一种重要的优化技术:谓词上拉。它可以进一步优化查询。
三、谓词上拉 本节介绍另外一种谓词的优化技术--谓词上拉。从名字理解,读者可能会直观地认为这是一种反向的优化策略,用来延迟谓词的过滤。笔者需要强调,这种理解是错误的。谓词上拉并不是谓词下推的反向优化。它主要是将内层子查询中的谓词“上拉”到外层查询中,参与外层的谓词推导过程,帮助生成更多有意义的谓词。接下来,我们继续通过分析 Q1 的优化点,来向读者介绍一些谓词上拉的场景。
1、谓词上拉
?V2 视图中存在一个 Having 谓词
M2 > 0
。对主查询来说,V2 的输出必然满足了 V2.M2 > 0
;结合主查询中已有谓词 V1.M1 > V2.M2
,我们可以推导得到 V1.M1 > 0
。显然,这个推导谓词可以下推到 V1 视图中。读者可以回忆上一篇中介绍的推导技术。V1
根据 MAX(C3) > 0
可以进一步推导产生一个 Where 过滤谓词 C3 > 0
。上拉 M2 > 0,推导 M1 > 0 并推入 V1,再次推导生成 C3 > 0 V1-3: SELECT C1, 0 AS C2, MAX(C3) AS M1
FROM T1 WHERE C1 > 10 AND C3 > 0
GROUP BY C1
2、常量上拉
V1 视图中存在一个特殊的投影表达式
0 AS C2
。对主查询来说,V1 的输出必然满足了 V1.C2 = 0
;结合主查询中已有的谓词 V1.C2 = V2.C2
,我们可以推导得到 V2.C2 = 0
。显然,这个谓词也可以推入到 V2
中。?
上拉 V1.C2 = 0,推导 V2.C2 = 0 并推入 V2V2-1: SELECT C1, C2, AVG(C3) AS M2
FROM T2 WHERE C1 > 10 AND C2 = 0
GROUP BY C1, C2 HAVING M2 > 0
可以看到,谓词上拉主要作用是把一个内联视图中的谓词“上拉”到主查询中,它可以参与主查询的谓词推导,帮助产生更多新谓词。这些新生成的谓词又会获得新的下压机会。综合三种优化技术,Q1 可以最终被优化为:
Q1 最终优化形式:
SELECT V1.C1, V1.C2, V1.M1, V2.M2
FROM
(SELECT C1, 0 AS C2, MAX(C3) AS M1
FROM T1
WHERE C1 > 10 AND C3 > 0
GROUP BY C1) V1,
(SELECT C1, C2, AVG(C3) AS M2
FROM T2
WHERE C1 > 10 AND C2 = 0
GROUP BY C1, C2 HAVING M2 > 0) V2
WHERE V1.C1 = V2.C1 AND V1.M1 > V2.M2;
四、总结 【SQL 改写系列七(谓词移动)】本文主要介绍了谓词移动的技术。它包含两个方面,谓词下推和谓词上拉。前者负责尽可能提前去执行过滤谓词,减少后续操作需要处理的数据量;后者主要构造更多的谓词来参与推导过程,强化推导的效果。谓词推导和谓词移动是互相协作、互相强化的,它们是非常重要的两项谓词优化技术。本文介绍了部分下推和上拉的场景,帮助读者理解这两个策略的概念和作用。针对谓词的优化还有很多可以介绍的内容。未来有机会,我们会继续介绍一些 OceanBase 在谓词推导或者移动方面积累的优化能力。
推荐阅读
- API|淘宝API接口大全
- 数据库|Redisson 高性能 Redis 分布式锁源码分析
- 容器化 | 在 Rancher 中部署 MySQL 集群
- 数据库|为什么要分库分表?
- java基础学习|mybatis-plus的介绍和使用
- 学习笔记|MySQL-多表查询-联合查询/子查询
- 学习笔记|MySQL-DQL-条件查询/聚合函数/分组查询/排序查询/分页查询
- 学习笔记|MySQL-约束
- JDBC|连接池-归还连接详解(上)