乐趣区

关于oceanbase:SQL-改写系列六谓词推导

系列文章导读

OceanBase 是 100% 自主研发,间断 9 年稳固撑持双 11,翻新推出“三地五核心”城市级容灾新规范,是 寰球惟一 在 TPC-C 和 TPC-H 测试上都刷新了世界纪录的国产原生分布式数据库,于 2021 年 6 月份正式凋谢源代码。查问优化器是关系数据库系统的外围模块,是数据库内核开发的重点和难点,也是掂量整个数据库系统成熟度的“试金石”。为了帮忙大家更好地了解 OceanBase 查问优化器,咱们将撰写查问改写系列文章,带大家更好地把握查问改写的精华,相熟简单 SQL 的等价性,写出高效的 SQL。本文是 OceanBase 改写系列第六篇,将重点介绍谓词推导,欢送探讨~

专栏作者介绍

OceanBase 优化器团队,由 OceanBase 高级技术专家溪峰、技术专家山文等领衔,致力于打造寰球当先的分布式查问优化器。

系列内容形成

本次查问改写系列不仅包含子查问优化、聚合函数优化、窗口函数优化、简单表达式优化四大模块,本文将会针对谓词的推导形式进行具体论述,还有更多模块内容,敬请期待。

欢送关注 OceanBase 开源用户群(钉钉号:33254054),进群与 OceanBase 查问优化器团队一起交换。

一、为什么须要谓词推导

业务在拜访数据库时通常只会读取局部数据,因而会指定一些谓词来过滤掉不须要的数据。实现一个查问语义时,咱们能够采纳多种不同的谓词组合。

例如:Q1 和 Q2 都是从数据库中读取编号为 1024 排片的余票信息。这两条查问应用了不同的谓词汇合,实现了雷同的查问成果。从查问的性能而言,Q2 的过滤谓词写的更好。Q2 中的 T.play_id = 1024 是一个基表过滤谓词。它能够提前过滤掉一批数据,缩小参加连贯的数据量。进一步的,当 TICKETS 表上存在 (play_id, sale_date, seat) 的索引时,查问优化器一方面能够确定出一个十分好的数据扫描范畴;另一方面还能够利用索引序打消 ORDER BY 产生的排序操作。最终,整个查问最多只须要读取 T 表的 10 行数据。

Q1:
SELECT P.show_time, T.ticket_id, T.seat
FROM PLAY P, TICKETS T
WHERE P.play_id = T.play_id AND P.play_id = 1024 AND T.sale_date is NULL
ORDER BY T.seat LIMIT 10;

Q2:
SELECT P.show_time, T.ticket_id, T.seat
FROM PLAY P, TICKETS T
WHERE T.play_id = 1024 and P.play_id = 1024 AND T.sale_date is NULL
ORDER BY T.seat LIMIT 10;

为了保障良好的查问性能,数据库内核须要有能力为 Q1 来查问推导出 T.play_id = 1024 这样的谓词。这种能力咱们称之为“谓词推导”。在 OceanBase 中,咱们针对不同的谓词应用场景,设计和实现了多种谓词推导的策略。下文将次要介绍这些推导策略。

二、谓词推导

谓词推导是依据多个谓词,推导失去一些新的谓词。例如,Q1 中存在 P.play_id = T.play_id 和 P.play_id = 1024 两个谓词,能够推导失去一个新的谓词 T.play_id = 1024。这是一个 T 表上的单表过滤谓词,它能够提前过滤掉 T 表上的数据,缩小参加多表连贯的数据量。推导出新谓词在很多优化场景都是有意义的。

大小比拟推导

给定多个大小比拟的谓词,咱们能够排列出多个表达式之间的大小关系。例如,上面这个查问中,存在 T1.C1 > T2.C1 和 T1.C1 < 10 两个谓词,那么咱们能够排列出它们之间的大小关系为:T2.C1 <T1.C1 < 10。显然,针对这种场景,咱们能够推导出一个新的谓词 T2.C1 < 10。这个谓词能够提前过滤 T2 表的数据,缩小参加连贯的数据量。

SELECT * FROM T1, T2 WHERE T1.C1 > T2.C1 AND T1.C1 < 10;

SELECT * FROM T1, T2 WHERE T1.C1 > T2.C1 AND T1.C1 < 10 AND T2.C1 > 10;

对 Q1 查问来说,咱们也是能够依据谓词给定的大小关系(T.play_id = P.play_id = 1024),推导出一个新的谓词 T.play_id = 1024。进一步的,推导出新的谓词后,咱们还能够打消一个冗余的连贯谓词 P.play_id = T.play_id,最终失去查问 Q2。

简单谓词推导

除了大小比拟、等值比拟的谓词外,查问中也常常会用到一些更加简单的谓词。例如,应用 LIKE 对字符串进行前缀匹配等。给定一个简单谓词和一些等值比拟关系,咱们也能够推导出一些新的谓词进去。例如,上面的查问中存在 T1.C1 = T2.C1 和 T1.C1 LIKE ‘ABC%’ 两个谓词。因为 T1.C1 和 T2.C1 存在等值关系,因而,T2.C1 LIKE ‘ABC%’ 也必然成立。这个谓词同样能够提前过滤 T2 表的数据,缩小参加连贯的数据量。

SELECT *
FROM T1, T2 WHERE T1.C1 = T2.C1 AND T1.C1 LIKE 'ABC%';

SELECT *
FROM T1, T2 WHERE T1.C1 = T2.C1 AND T1.C1 LIKE 'ABC%' AND T2.C1 LIKE 'ABC%';

给定两个列之间的等值关系,以及其中一个列上的任意谓词,咱们简直能够推导产生另外一个列上的谓词。但这并不意味着,咱们总要推导出新谓词。一些简单谓词自身的计算代价可能就比拟昂扬,并且谓词自身的过滤性并不好,推导产生新的简单谓词反而 会导致查问性能降落 。理论在决策时, 应该首先判断推导失去的新谓词是否能够过滤掉掉大量的数据

OR 谓词推导

OR 谓词在业务查问中也很常见。上面这个查问中,存在一个很乏味的 OR 谓词。首先,这个谓词援用到了多个表的数据,因而,这个谓词只能过滤多表连贯之后的后果。乏味之处在于:这个 OR 的每个分支中,都蕴含了 T1 表上的谓词。咱们能够结构出 T1 表上的过滤谓词:T1.C2 = 1 OR T1.C2 =2。这是一个单表过滤谓词,能够提前过滤 T1 的数据,缩小参加连贯的行数。

SELECT * FROM T1, T2 
WHERE T1.C1 = T2.C1 AND 
     ((T1.C2 = 1) OR (T1.C2 = 2 AND T2.C2 = 2))
     
SELECT * FROM T1 ,T2
WHERE T1.C1 = T2.C1 AND 
      (T1.C2 = 1 OR T1.C2 = 2) AND
      ((T1.C2 = 1) OR (T1.C2 = 2 AND T2.C2 = 2));

MIN/MAX 谓词推导

以上两种场景的推导相对而言是比拟直观的。上面咱们介绍一种更“费解”的谓词推导形式。

在上面这个查问中,存在一个 MAX(C2) > 10 的 HAVING 谓词。依据这个谓词,咱们能够推导产生一个 C2 > 10 的过滤谓词。这里的合理性在于:原始查问最终仅保留 MAX(C2) > 10 的分组聚合后果,如果给定一行不满足 C2 > 10,存在以下两种状况:

1、这一行不是同一分组内 C2 的最大值(对分组聚合没有意义,能够过滤)

2、这一行是同一分组内 C2 的最大值(会被 HAVING 谓词过滤)

在以上两种状况下,不满足 C2 > 10 的数据都是能够提前过滤的。因而,咱们能够推导出一个新的谓词 C2 > 10。

SELECT C1, MAX(C2)
FROM T1
GROUP BY C1 HAVING MAX(C2) > 10;

=>

SELECT C1, MAX(C2)
FROM T1
WHERE C2 > 10
GROUP BY C1 HAVING MAX(C2) > 10;

相似的,给定如下带 MIN 聚合函数的查问,咱们也能够推导产生一个新的谓词。这些谓词能够提前过滤掉局部数据,缩小分组聚合操作的计算量,晋升查问性能。

SELECT C1, MIN(C2)
FROM T1
GROUP BY C1 HAVING MIN(C2) < 10;

=>

SELECT C1, MIN(C2)
FROM T1
WHERE C2 < 10
GROUP BY C1 HAVING MIN(C2) < 10;

这种推导形式对查问的状态是有较多性质的。读者能够考虑一下,如果查问中存在其余的聚合函数,是否还能够做如上的谓词推导?

推导陷阱

推导新谓词也存在一些容易犯错的陷阱。例如:思考如下查问 Q3,咱们是否能够依据 T1.C_CI = ‘A’ 和 T1.C_CI = T2.C_BIN 推导产生一个新的谓词 T2.C_BIN = ‘A’?

这种推导形式是谬误的。

这是因为,这里的谓词进行比拟时,比拟的形式并不相同。在 T1.C_CI = ‘A’ 中,字符串比拟时大小写不敏感的,即:’a’, ‘A’ 等均满足过滤条件。但 T1.C_CI = T2.C_BIN 是依照大小写敏感的形式比拟字符串。联合这两个谓词,仅能推断出:T2.C_BIN 的取值为 ‘a’ 或者 ‘A’。然而 T2.C_BIN = ‘A’ 是大小写敏感的比拟,它会间接过滤掉取值为 ‘a’ 的数据。因而,推导产生这个新谓词是不正确的。

CREATE TABLE T1 (C_CI VARCHAR(10) UTF8_GENERAL_CI);
CREATE TABLE T2 (C_BIN VARCHAR(10) UTF8_BIN);

Q3: SELECT * FROM T1, T2 
    WHERE T1.C_CI = 'ABC' AND T1.C_CI = T2.C_BIN;

=>

Q4: SELECT * FROM T1, T2 
    WHERE T1.C_CI = 'ABC' AND T1.C_CI = T2.C_BIN AND T2.C_BIN = 'ABC';

三、总结

本文次要介绍了一些谓词的推导形式。推导新谓词对查问优化而言是十分重要的。基于新的谓词,查问优化器能够抉择更好的索引,生成更好的基表拜访门路。因而,谓词推导是一项十分重要的优化技术。谓词相干的优化还有很多,在下一篇文章中,咱们将介绍谓词挪动的技术。它会调整谓词在查问中的地位,将谓词挪动到更正当的地位,提上整个查问的性能。

退出移动版