首批通过分布式安全可靠测评,为关键业务系统打造
概述
更新时间:2026-03-19 17:33:37
数据库中的查询改写(Query Rewrite)是指将一个 SQL 改写成另外一个更加容易优化的 SQL。
OceanBase 数据库提供了两类查询改写规则:基于规则的改写与基于代价的改写。
基于规则的查询改写 总是会把 SQL 往"好"的方向进行改写,从而增加该 SQL 的优化空间。例如,将子查询转换为联接操作是典型的规则改写,它拓展了优化器考虑的执行方案,如 Hash Join 和 Merge Join,而非仅限于 Nested Loop Join。
基于代价的查询改写 并不能总是把 SQL 往"好"的方向进行改写,它依赖于成本模型来评估是否应该执行改写。例如,OR-Expansion 就是一种代价驱动的改写策略。
在数据库中,应用一个改写规则需满足特定条件,不同规则之间还可能相互触发。OceanBase 数据库将规则改写分为多个集合,并采用迭代方法对每个集合进行处理,直至无法进一步改写或达到预设的迭代次数限制。基于代价的改写规则也以类似的迭代方式处理。
值得注意的是,基于代价的改写可能会触发基于规则的改写,因此在整体上,OceanBase 数据库的查询改写实际上是通过迭代这两种策略来进行的。
SQL 的查询改写规则
OceanBase 数据库支持的查询改写规则:基于规则的改写与基于代价的改写。
在数据库查询优化中,规则模型和代价模型是决定查询如何被改写和执行计划被选择的两个关键因素。它们的目的是提升SQL查询的性能。下面分别介绍一些常见的规则模型和代价模型。
规则模型(基于规则的查询改写)
规则模型通常基于固定的启发式规则来改写查询。以下是一些典型的规则改写策略:
子查询相关改写:
- 视图合并(View Merging):把视图内嵌的查询合并到主查询中,减少层次,提高执行效率。
- 子查询展开(Subquery Unnesting):子查询展开是将
WHERE条件中子查询提升到父查询中,并作为联接条件与父查询并列进行展开。转换后子查询将不存在,外层父查询中会变成多表联接。
ANY/ALL使用MAX/MIN改写:- 将包含
ANY或ALL操作符的子查询改写为使用聚合函数MAX或MIN的形式,以便可能应用索引或更有效的执行策略。
- 将包含
外联接消除(Outer Join Elimination):
- 当外联接的结果不影响最终结果集时,消除外联接,转换为内联接或简单的
SELECT,简化查询。
- 当外联接的结果不影响最终结果集时,消除外联接,转换为内联接或简单的
简化条件改写:
HAVING条件消除:如果查询中没有聚集操作和GROUP BY,则HAVING可以合并到WHERE条件中,并将HAVING条件删除,从而可以将HAVING条件在WHERE条件中统一管理,并做进一步优化。- 等价关系推导:等价关系推导是指利用比较操作符的传递性,推倒出新的条件表达式,从而减少需要处理的行数或者选择到更有效的索引。
- 恒真/假消除:移除查询条件中总是为真或为假的部分,简化查询逻辑。
非SPJ(Select-Project-Join)的改写:
- 冗余排序消除(Redundant Order By Elimination):如果查询结果不要求特定顺序或排序无效果,则消除排序操作。
- LIMIT下压子查询:当
LIMIT可以应用于子查询而不影响最终结果时,下压LIMIT到子查询中减少处理的行数。 - LIMIT下压外连接或交叉连接:将
LIMIT应用于外连接或交叉连接的适当部分,减少不必要的行处理。 - DISTINCT消除:如果可以保证结果集中的行已经唯一,则移除
DISTINCT操作。 - MIN/MAX改写:在适当的情况下,将查询改写为更有效的形式来计算
MIN或MAX值,例如通过索引访问。
代价模型(基于代价的查询改写)
代价模型依赖于成本估算来选择最优的查询执行计划。以下是 OceanBase 数据库所支持的基于代价评估的策略:
- OR-Expansion:将含有OR条件的谓词拆分成多个独立的查询,并将结果集合并,有时这样做可以利用索引或并行处理来提升性能。
OceanBase 数据库使用代价模型来估算查询操作的资源消耗,该模型基于一组公式和常数参数来评估执行算子的成本。例如,EXCHANGE IN 算子的成本可以用以下公式表示:
cost = rows * row_width * NETWORK_TRANS_PER_BYTE_COST +
rows * row_width * NETWORK_DESER_PER_BYTE_COST
这里,公式包括了算子输出行数 rows 和数据宽度 row_width 两个因素,并结合网络传输成本 NETWORK_TRANS_PER_BYTE_COST 与数据反序列化成本 NETWORK_DESER_PER_BYTE_COST 来计算总开销。
OceanBase 数据库的自适应代价模型关键在于调整这些成本系数以匹配特定的硬件环境。尽管可以在数据库安装时通过自动化脚本尝试计算新的成本系数,但是由于优化器使用到的代价系数太多、测算过程过于复杂,虽然有自动化脚本,但是整个测算过程过于复杂,出错的概率太大,用户体验可能会非常差。
为了简化系数的适应性调整,可以将代价模型的系数归一化为以下几个主要硬件参数的函数,可以把当前使用到的代价模型系数归一化成这四个基本系数的组合。
- CPU 频率(CPU_SPEED)
- 硬盘顺序读取速率
- 硬盘随机读取速率
- 网络带宽
例如,哈希表探测的成本系数可转换为 CPU 指令数(CPU_CYCLES),结合 CPU 频率转换为当前环境下哈希表探测的成本:
PROBE_HASH_PER_ROW_COST = CPU_CYCLES * CPU_SPEED;
通过这种归一化方法,就可以把代价模型的系数与当前硬件解耦,通过使用不同的系统统计信息换算,就可以得倒不同硬件环境的代价系数。
OceanBase 数据库当前的代价模型支持自适应功能,能够根据实时硬件性能评估计划开销,并为用户提供了手动调整代价系数的接口,以便在必要时定制优化策略。