An Overview of Query Optimization in Relational Systems

Surajit Chaudhuri, PODS 1998

系统地回顾与分析关系数据库中查询优化(query optimization)的关键技术、挑战和实现方法。本文总结了传统关系系统优化器的构造模块、优化流程,以及现实系统中设计取舍。

查询优化器 (Query Optimizer) 的角色

当用户写一条 SQL:

SELECT a, b FROM R JOIN S ON R.x = S.x WHERE R.y > 100;

数据库系统可以有很多种执行方式:

  • 扫描 R、扫描 S,然后 Nested-Loops Join
  • 用索引扫描 R、再 Hash Join
  • 用索引扫描 S、再 Merge Join
  • 甚至改变连接顺序、重新排列谓词顺序 (predicate pushdown)

如果系统盲目执行某一种方式,可能会非常慢。查询优化器的职责是:

  • 把高层 SQL / 关系代数 → 转成逻辑计划 (logical plan)
  • 枚举可能的执行计划 (physical plan)
  • 估算每个计划代价 (cost)
  • 选择一个最优 / 足够优的计划去执行

正是因为优化器,关系数据库才能兼顾 声明式接口 (SQL) 与 高性能执行。

查询优化器负责将用户的 SQL / 关系代数表达转化为高效执行计划 (execution plan),是连接关系模型与物理实现的桥梁。优化器的存在,使得关系数据库既能保持声明式接口 (SQL),又能获得高性能。

查询优化划分为若干阶段:

  • 解析与逻辑重写 (Parsing & Logical Rewrite)
    • 将 SQL 转为逻辑查询 / 代数表达 (logical plan),并进行语义、语法检查。
    • 对表达进行逻辑重写 (logical rewrite):例如谓词下推 (predicate pushdown)、冗余消除、视图展开 (view expansion)、连接 (join) 重写、子查询优化等优化。
  • 代价模型 (Cost Model)
    • 对每个可能执行计划 (access path / join order / join algorithm) 估算代价 (估计 I/O、CPU、内存等),作为优化决策依据。
    • 代价模型是优化器决策质量的基础。假设统计 (statistics) 与估算 (estimation) 的准确性极其关键。
  • 访问路径与连接算法 (Access Paths & Join Algorithms)
    • 支持多种访问路径 (seq scan、indexed scan等) 与连接算法 (nested-loop join, hash join, sort-merge join 等)。
    • 优化器需要根据数据特点 (基数、分布、索引、排序状态等) 选择合适路径。
  • 计划枚举与搜索 (Plan Enumeration / Search)
    • 因为可能的计划组合很多 (join order, index usage, join method……),优化器需要枚举 (或以启发式 / 动态编程 /代价 pruning) 搜索空间。
    • SELECT … JOIN … WHERE … GROUP BY … 的复杂查询,其可能计划数目指数级增长,因此枚举与剪枝策略对效率非常关键。
  • 统计与估算 (Statistics & Estimation)
    • 优化器对基数 (cardinality)、数据分布 (histogram / distinct counts / null ratios / correlation) 的统计数据进行收集,并据此估算中间结果规模。
    • 估算偏差会严重影响优化结果,导致次优计划。

System R/Starburst 是 bottom-up 类型的优化器,Volcano/Cascades 是 top-down 类型的优化器。