OBCP第三章、SQL引擎高级技术-查询改写

简介: OBCP第三章、SQL引擎高级技术-查询改写

查询改写概念

数据库中的查询改写(query rewrite)把一个 SQL 改写成另外一个更加容易优化的SQL。


1.基于规则的查询改写总是会把SQL往“好”的方向进行改写,从而增加该SQL的优化空间


2.基于规则的查询改写并不能总是把 SQL 往“好”的方向进行改写,所以 需要代价模型来判断


3.基于代价的改写之后可能又会重新触发基于规则的改写,所以整体上采用 迭代式的方式进行改写

基于规则的查询改写

基于规则的查询改写方式主要包括:

子查询相关改写

视图合并、子查询展开、ANY/ALL 使用 MAX/MIN 改写

外联接消除

简化条件改写

    HAVING 条件消除、等价关系推导、恒真/假消除

非SPJ的改写

冗余排序消除、LIMIT 下压、DISTINCT 消除、MIN/MAX 改写

子查询相关改写

子查询改写的方式主要包括视图合并、子查询展开和将 ANY/ALL使用MAX/MIN改写等


优化器对于子查询一般使用嵌套执行的方式,也就是父查询每生成一行数据后,都需要执行一次子查询。使用这种方式需要多次执行子查询,执行效率很低。对于子查询的优化方式,一般会将其改写为联接操作,可大大提高执行效率,主要优点如下:


可避免子查询多次执行

优化器可根据统计信息选择更优的连接顺序和连接方法

子查询的连接条件、过滤条件改写为父查询的条件后,优化器可以进行进一步优化,比如条件下压等

子查询相关改写-视图合并

视图合并是指将代表一个视图的子查询合并到包含该视图的查询中,视图合并后,有助于优化器增加联接顺序的选择、访问路径的选择以及进一步做其他改写操作,从而选择更优的执行计划。


创建相关测试表 SQL_A 不进行改写,可选连接顺序有:


•t1, v(t2,t3)


•t1, v(t3,t2)


•v(t2,t3), t1


•v(t3,t2), t1


视图合并改写SQL_B后,可选连接顺序有:


•t1, t2, t3


•t1, t3, t2


•t2, t1, t3


•t2, t3, t1


•t3, t1, t2


•t3, t2, t1


子查询展开:子查询展开为semi-join/anti-join


子查询展开是指将 where 条件中子查询提升到父查询中,并作为连接条件与父


查询并列进行展开。 一般涉及的子查询表达式有 not in、in、not exist、exist、any、all。


两表结构:

t1 (c1 INT, c2 INT)
t2 (c1 INT PRIMARY KEY, c2 INT)

其中t2.c2 不具有唯一性,改为 semi join,改写后执行计划如下所示


子查询展开的方式如下:

改写条件使生成的联接语句能够返回与原始语句相同的行

展开为半联接(SEMI JOIN / ANTI JOIN)

子查询展开:子查询展开为内连接

子查询展开是指将 where 条件中子查询提升到父查询中,并作为连接条件与父查询并列进行展开。 一般涉及的子查询 表达式有 not in、in、not exist、exist、any、all。

外连接消除

外联接操作可分为左外联接、右外联接和全外联接。在联接过程中,由于外联接左右顺序不能变换,优化器对联接顺序的选择会受到限制。


外连接消除是指将外连接转换成内连接,从而可以提供更多可选择的连接路径,供优化器考虑。外连接消除需要存在 “空值拒绝条件”,即 where 条件中,存在当内表生成的值为 null 时,使得输出为 false 的条件。

SELECT t1.c1, t2.c2 FROM t1 LEFT JOIN t2 ON t1.c2 = t2.c2;


SELECT t1.c1, t2.c2 FROM t1 LEFT JOIN t2 ON t1.c2 = t2.c2 WHERE t2.c2 > 5;
SELECT t1.c1, t2.c2 FROM t1 INNER JOIN t2 ON t1.c2 = t2.c2
WHERE t2.c2 > 5;

基于代价的查询改写

OceanBase目前只一种支持基于代价的查询改写 - 或展开(Or-Expansion)


或展开(Or-Expansion):把一个查询改写成若干个用union all组成的子查询,这个改写可能会给每个子查询提供更优的优化空间,但是也会导致多个子查询的执行,所以这个改写需要基于代价去判断


通常来说,Or-Expansion的改写主要有如下三个作用:


允许每个分支使用不同的索引来加速查询

允许每个分支使用不同的连接算法来加速查询,避免使用笛卡尔连接

允许每个分支分别消除排序,更加快速的获取top-k结果

允许每个分支使用不同的索引来加速查询


如上图所示 :查询 SQL_A会被改写成SQL_B 的形式,其中SQL_B中的谓 词LNNVL(t1.a = 1)保证了这两个子查询不会生成重复的结果


如果不进行改写,SQL_A一般来说会选择主表作为访问路径,对于SQL_B 来说,如果t1表上存在索引(a)和索引(b),那么该改写可能会让SQL_B中的每一个子查询选择索引作为访问路径。

允许每个分支使用不同的索引来加速查询

如果不进行OR-EXPANSION的改写,该查询只能使用主表访问路径,执行计划如下:

允许每个分支使用不同的联接算法来加速查询

被改写之后,每个子查询都使用了Hash Join,执行计划如下:


允许每个分支分别消除排序

CREATE TABLE t1(a INT, b INT, INDEX IDX_a(a, b));

SQL_A

SELECT * FROM t1 
WHERE t1.a = 1 OR t1.a = 2 
ORDER BY b LIMIT 10;

SQL_B:

SELECT * FROM 
(SELECT * FROM t1 
WHERE t1.a = 1 
ORDER BY b LIMIT 10 
UNION ALL
SELECT * FROM t1 
WHERE t1.a = 2 
ORDER BY b LIMIT 10
) AS TEMP
ORDER BY temp.b LIMIT 10;

如上图所示,查询SQL_A会被改写成SQL_B      


对于SQL_A来说,执行方式是只能把满足条件的行数找出来,然后进行排序,最终取TOP-10结果


对于SQL_B来说,如果存在索引(a,b), 那么SQL_B中的两个子查询都可以使用索引把排序消除,每个子查询取TOP-10结果,然后最终对这20行数据排序一次获取最终的TOP-10行。


因此每个分支分别消除排序,可以更加快速的获取TOP-K结果。

允许每个分支分别消除排序

不改写的话,需要排序最终获取TOP-K结果,执行计划如下:

EXPLAIN SELECT/*+NO_REWRITE()*/*FROM t1 WHERE t1.a = 1 OR t1.a = 2 
ORDER BY b LIMIT 10;


允许每个分支分别消除排序

进行改写的话,排序算子可以被消除,最终获取 TOP-K 结果,执行计划如下:

EXPLAIN SELECT * FROM t1 WHERE t1.a = 1 OR t1.a = 2 ORDER BY b LIMIT 10;



相关文章
|
4月前
|
SQL 数据挖掘 数据库
第三篇:高级 SQL 查询与多表操作
本文深入讲解高级SQL查询技巧,涵盖多表JOIN操作、聚合函数、分组查询、子查询及视图索引等内容。适合已掌握基础SQL的学习者,通过实例解析INNER/LEFT/RIGHT/FULL JOIN用法,以及COUNT/SUM/AVG等聚合函数的应用。同时探讨复杂WHERE条件、子查询嵌套,并介绍视图简化查询与索引优化性能的方法。最后提供实践建议与学习资源,助你提升SQL技能以应对实际数据处理需求。
288 1
|
1月前
|
SQL 人工智能 数据库
【三桥君】如何正确使用SQL查询语句:避免常见错误?
三桥君解析了SQL查询中的常见错误和正确用法。AI产品专家三桥君通过三个典型案例:1)属性重复比较错误,应使用IN而非AND;2)WHERE子句中非法使用聚合函数的错误,应改用HAVING;3)正确的分组查询示例。三桥君还介绍了学生、课程和选课三个关系模式,并分析了SQL查询中的属性比较、聚合函数使用和分组查询等关键概念。最后通过实战练习帮助读者巩固知识,强调掌握这些技巧对提升数据库查询效率的重要性。
84 0
|
6月前
|
SQL 索引
【YashanDB知识库】字段加上索引后,SQL查询不到结果
【YashanDB知识库】字段加上索引后,SQL查询不到结果
|
2月前
|
SQL
SQL中如何删除指定查询出来的数据
SQL中如何删除指定查询出来的数据
|
4月前
|
SQL 关系型数据库 MySQL
凌晨2点报警群炸了:一条sql 执行200秒!搞定之后,我总结了一个慢SQL查询、定位分析解决的完整套路
凌晨2点报警群炸了:一条sql 执行200秒!搞定之后,我总结了一个慢SQL查询、定位分析解决的完整套路
凌晨2点报警群炸了:一条sql 执行200秒!搞定之后,我总结了一个慢SQL查询、定位分析解决的完整套路
|
3月前
|
SQL 存储 弹性计算
OSS Select 加速查询:10GB CSV 文件秒级过滤的 SQL 语法优化技巧
OSS Select 可直接在对象存储上执行 SQL 过滤,跳过文件下载,仅返回所需数据,性能比传统 ECS 方案提升 10~100 倍。通过减少返回列、使用等值查询、避免复杂函数、分区剪枝及压缩优化等技巧,可大幅降低扫描与传输量,显著提升查询效率并降低成本。
|
6月前
|
SQL 大数据 数据挖掘
玩转大数据:从零开始掌握SQL查询基础
玩转大数据:从零开始掌握SQL查询基础
254 35
|
6月前
|
SQL 关系型数据库 MySQL
如何优化SQL查询以提高数据库性能?
这篇文章以生动的比喻介绍了优化SQL查询的重要性及方法。它首先将未优化的SQL查询比作在自助餐厅贪多嚼不烂的行为,强调了只获取必要数据的必要性。接着,文章详细讲解了四种优化策略:**精简选择**(避免使用`SELECT *`)、**专业筛选**(利用`WHERE`缩小范围)、**高效联接**(索引和限制数据量)以及**使用索引**(加速搜索)。此外,还探讨了如何避免N+1查询问题、使用分页限制结果、理解执行计划以及定期维护数据库健康。通过这些技巧,可以显著提升数据库性能,让查询更高效流畅。
|
6月前
|
SQL 存储 自然语言处理
YashanDB SQL 引擎
YashanDB SQL 引擎
|
6月前
|
SQL 缓存 关系型数据库
SQL为什么不建议执行多表关联查询
本文探讨了SQL中不建议执行多表关联查询的原因,特别是MySQL与PG在多表关联上的区别。MySQL仅支持嵌套循环连接,而不支持排序-合并连接和散列连接,因此在多表(超过3张)关联查询时效率较低。文章还分析了多表关联查询与多次单表查询的效率对比,指出将关联操作放在Service层处理的优势,包括减少数据库计算资源消耗、提高缓存效率、降低锁竞争以及更易于分布式扩展等。最后,通过实例展示了如何分解关联查询以优化性能。
221 0