当前位置: 首页 > news >正文

询优化器<1>查询重写 / 逻辑优化

前置知识

语法树

ASTAbstract Syntax Tree,中文通常叫抽象语法树

在数据库里,用户写的 SQL 文本会先经过词法分析和语法分析,被转换成一种树形结构,这棵树就是 AST。它描述的是 SQL 的语法结构,而不是最终怎么执行。

例如 SQL:

SELECT name, age FROM users WHERE age > 18;

可以抽象成一棵 AST:

SelectStatement ├── SelectList │ ├── Column: name │ └── Column: age ├── From │ └── Table: users └── Where └── GreaterThan ├── Column: age └── Literal: 18

它的意思是:

这是一个 SELECT 查询 查询的列是 name 和 age 查询的表是 users 过滤条件是 age > 18

AST 的作用主要有三个:

  1. 让数据库理解 SQL 的结构
    SQL 文本只是字符串,数据库不能直接优化字符串,必须先把它变成结构化形式。
  2. 为语义分析做准备
    例如检查users表是否存在、age列是否存在、类型是否匹配、函数是否合法等。
  3. 为逻辑计划生成做准备
    数据库会根据 AST 生成逻辑查询计划,例如选择、投影、连接等关系代数表达式。

可以把整个流程理解为:

SQL 文本 → 词法分析:拆成 token → 语法分析:生成 AST → 语义分析:检查表名、列名、类型 → 逻辑计划:关系代数表达式 → 逻辑优化:查询重写 → 物理计划:选择具体执行算法 → 执行

简单说:

AST 是数据库把 SQL 从“字符串”变成“结构化语法表示”的第一步。

它还不是执行计划,只是 SQL 的语法骨架。

逻辑查询计划

逻辑查询计划是数据库把 SQL 的含义转换成的一种关系代数形式的操作树。它描述“要做哪些逻辑操作”,但还不决定“具体用什么物理算法执行”。

可以理解为:

SQL 文本 → AST 抽象语法树 → 语义分析 → 逻辑查询计划 → 逻辑优化 → 物理执行计划 → 执行

1. 逻辑查询计划描述什么

逻辑查询计划主要描述这些逻辑算子:

SQL 部分逻辑算子
FROM表扫描
WHERE选择 / 过滤σ
SELECT投影π
JOIN连接
GROUP BY分组聚合γ
HAVING聚合后过滤
DISTINCT去重
ORDER BY排序
LIMIT限制输出行数

例如 SQL:

SELECT name FROM users WHERE age > 18;

可以转换成逻辑查询计划:

Projection[name] └── Selection[age > 18] └── TableScan[users]

用关系代数表示就是:

π_name(σ_age>18(users))

意思是:

  1. users表取数据;
  2. 过滤age > 18的行;
  3. 只输出name列。

2. 逻辑查询计划不是物理执行计划

逻辑查询计划只说明做什么,不说明怎么做

例如:

SELECT * FROM orders o JOIN customers c ON o.customer_id = c.customer_id;

逻辑查询计划可能是:

Join[o.customer_id = c.customer_id] ├── TableScan[orders] └── TableScan[customers]

它只说明要把orderscustomers按条件连接起来。

但它还没有决定:

用 Hash Join 还是 Nested Loop Join? 先扫描 orders 还是先扫描 customers? 用全表扫描还是索引扫描? 是否并行执行? 内存如何分配?

这些属于物理执行计划阶段。


3. 逻辑查询计划和 AST 的区别

AST 是 SQL 的语法结构,逻辑查询计划是 SQL 的关系操作语义

同一个 SQL:

SELECT name FROM users WHERE age > 18;

AST 更像:

SelectStatement ├── SelectList │ └── Column: name ├── From │ └── Table: users └── Where └── GreaterThan ├── Column: age └── Literal: 18

逻辑查询计划更像:

Projection[name] └── Selection[age > 18] └── TableScan[users]

区别是:

对比项AST逻辑查询计划
表示内容SQL 的语法结构查询的关系代数操作
更接近SQL 文本数据库内部执行语义
关注点SELECTFROMWHERE怎么写扫描、过滤、投影、连接怎么组合
是否可优化不方便直接优化适合做查询重写和逻辑优化

4. 一个 JOIN 查询的例子

SELECT c.name, o.amount FROM customers c JOIN orders o ON c.customer_id = o.customer_id WHERE c.region = 'Asia' AND o.amount > 100;

初始逻辑查询计划可能是:

Projection[c.name, o.amount] └── Selection[c.region = 'Asia' AND o.amount > 100] └── Join[c.customer_id = o.customer_id] ├── TableScan[customers] └── TableScan[orders]

关系代数表示:

π_c.name,o.amount( σ_c.region='Asia' AND o.amount>100( customers ⋈_c.customer_id=o.customer_id orders ) )

逻辑优化后,可以变成:

Projection[c.name, o.amount] └── Join[c.customer_id = o.customer_id] ├── Projection[c.customer_id, c.name] │ └── Selection[c.region = 'Asia'] │ └── TableScan[customers] └── Projection[o.customer_id, o.amount] └── Selection[o.amount > 100] └── TableScan[orders]

也就是:

π_c.name,o.amount( π_c.customer_id,c.name(σ_c.region='Asia'(customers)) ⋈_c.customer_id=o.customer_id π_o.customer_id,o.amount(σ_o.amount>100(orders)) )

这里做了两个重要优化:

选择下推:先过滤行 投影下推:先减少列

5. 总结

逻辑查询计划就是数据库把 SQL 转换成的“关系代数操作树”。

它回答的是:

这个查询在逻辑上需要扫描哪些表、过滤哪些行、保留哪些列、执行哪些连接、做哪些聚合。

但它还不回答:

具体用哪个索引、哪个连接算法、哪个扫描方式、多少并行度。

这些要到物理执行计划阶段才决定。

关系代数基础

下面用一个大表总结关系代数基础符号

符号名称作用输入输出SQL 对应示例说明
RST关系表示一张表或中间结果一个关系表名 / 子查询Student关系可以理解为数据库中的表
元组Tuple表中的一行一行数据一行记录(1, 'Alice', 20)关系由多个元组组成
属性Attribute表中的一列一列字段列名nameage属性组成关系的 schema
σ_p(R)选择按条件筛选行一个关系R满足条件的行WHEREσ_age>18(Student)横向筛选;保留满足谓词p的元组
π_A(R)投影选择需要的列一个关系R指定列组成的新关系SELECT 列π_name,age(Student)纵向裁剪;经典关系代数中投影会去重
R × S笛卡尔积两个关系的所有行两两组合两个关系组合后的关系FROM R, S/CROSS JOINStudent × DeptR有 m 行、S有 n 行,结果有m × n
R ⋈_p S条件连接 / θ 连接按条件连接两个关系两个关系满足连接条件的组合行JOIN ... ONStudent ⋈_Student.dept_id=Dept.dept_id Dept可理解为σ_p(R × S)
R ⋈ S自然连接自动按同名属性连接两个关系按同名列匹配后的关系NATURAL JOINStudent ⋈ Dept会合并同名属性;工程中要谨慎使用
R ⟕_p S左外连接保留左表所有行,右表无匹配则补 NULL两个关系左表完整保留的连接结果LEFT JOIN ... ONStudent ⟕_Student.dept_id=Dept.dept_id Dept不满足普通内连接的交换律
R ⟖_p S右外连接保留右表所有行,左表无匹配则补 NULL两个关系右表完整保留的连接结果RIGHT JOIN ... ONStudent ⟖_Student.dept_id=Dept.dept_id Dept可视为左右表交换后的左外连接
R ⟗_p S全外连接保留左右两边所有行,无匹配处补 NULL两个关系双方都完整保留的连接结果FULL OUTER JOINStudent ⟗_Student.dept_id=Dept.dept_id DeptSQL 支持情况因数据库而异
R ⋉_p S半连接返回R中能在S找到匹配的行两个关系只包含左表属性的关系EXISTS/INStudent ⋉_Student.dept_id=Dept.dept_id Dept不输出右表列;常用于子查询优化
R ▷_p S反连接返回R中不能在S找到匹配的行两个关系只包含左表属性的关系NOT EXISTS/NOT INStudent ▷_Student.dept_id=Dept.dept_id DeptNOT IN受 NULL 影响,实际优化要谨慎
R ∪ S合并两个关系的元组两个兼容关系出现在RS中的元组UNIONπ_name(Student) ∪ π_name(Teacher)要求两个关系属性个数和类型兼容
R ∩ S取两个关系共同的元组两个兼容关系同时出现在RS中的元组INTERSECTπ_name(Student) ∩ π_name(Teacher)不是所有数据库都直接支持INTERSECT
R − SR中去掉也在S中的元组两个兼容关系属于R但不属于S的元组EXCEPT/MINUSπ_name(Student) − π_name(Teacher)不满足交换律,即R − S ≠ S − R
ρ_x(R)关系重命名给关系改名一个关系改名后的关系表别名ρ_S1(Student)常用于自连接
ρ_{a/b}(R)属性重命名给属性改名一个关系改列名后的关系列别名ρ_{student_name/name}(Student)防止列名冲突或统一 schema
γ_G,F(R)分组聚合按属性分组并计算聚合函数一个关系聚合后的关系GROUP BYγ_dept_id,COUNT(*)(Student)G是分组列,F是聚合函数
δ(R)去重删除重复元组一个关系无重复元组的关系DISTINCTδ(Student)经典关系代数默认集合语义;SQL 默认多重集语义
τ_A(R)排序按属性排序一个关系有序结果ORDER BYτ_age DESC(Student)经典关系代数通常无序,排序属于扩展算子
LIMIT_n(R)限制行数只取前 n 行一个关系最多 n 行LIMIT/FETCH FIRSTLIMIT_10(Student)通常需要和排序一起使用才有确定意义
attrs(R)属性集合表示关系R的所有列一个关系属性集合schemaattrs(Student)常用于描述规则前提
attrs(p)谓词属性集合表示条件p用到的列一个谓词属性集合条件涉及列attrs(age > 18) = {age}常用于判断谓词能否下推
pq谓词过滤或连接条件表达式TRUE / FALSE / UNKNOWNWHERE/ONage > 18SQL 中还要考虑 NULL 三值逻辑
A ⊆ B子集表示属性集合包含关系两个集合布尔判断{name} ⊆ {id,name,age}常用于投影规则前提
等价表示两个表达式结果相同两个表达式等价关系查询重写σ_p(σ_q(R)) ≡ σ_{p AND q}(R)查询优化的理论基础

最核心的几个:

符号口诀SQL 对应
σ选行WHERE
π选列SELECT
连表JOIN
γ分组统计GROUP BY
∪ / ∩ / −集合运算UNION / INTERSECT / EXCEPT
ρ改名别名AS

回到顶部

查询重写 / 逻辑优化


回到顶部

一、查询重写 / 逻辑优化阶段的作用

在数据库系统中,用户提交的是 SQL 查询,而数据库内部通常不会直接执行 SQL 文本。SQL 会先被解析成一种内部表示,例如:

SQL 语句 → 语法树 AST → 逻辑查询计划 → 关系代数表达式 → 物理执行计划
http://www.cnnetsun.cn/news/3034218.html

相关文章:

  • 整个过程没有引入新的线程
  • XCPC 2026 WEEK 14
  • Java毕设选题推荐:基于 SpringBoot 的剧本杀门店预约管理平台的设计与实现 基于 SpringBoot 的沉浸式剧本杀服务系统【附源码、mysql、文档、调试+代码讲解+全bao等】
  • 【机器学习入门】从零到一入门机器学习
  • 合租守则第17条
  • 【毕业设计】基于 SpringBoot 的便民医疗咨询服务平台的设计与实现 基于 SpringBoot 的医疗知识问答共享平台(源码+文档+远程调试,全bao定制等)
  • Java计算机毕设之基于 Java 的在线医生问诊问答平台的设计与实现 基于 Java 的医疗咨询答疑管理系统(完整前后端代码+说明文档+LW,调试定制等)
  • Java毕设项目:基于 SpringBoot 的分级医疗问答服务管理平台的设计与实现 基于 SpringBoot 的医疗科普问答互动系统 (源码+文档,讲解、调试运行,定制等)
  • ECC安装与配置:把 Claude Code 装进一个能稳定发挥的 Harness
  • list列表常用的方法(python)
  • 复杂遮挡与动态干扰场景下跨镜轨迹智能补链与 ID 稳定技术
  • 2026年6月最新|苏州SEO/GEO优化公司推荐|7家本地服务商测评对比
  • 非煤矿山用工规范大限将至,无人驾驶矿卡迎来政策强驱动
  • Claude 桌面版深度使用技巧指南
  • 【Claude】Usage credits required for 1M context 报错已解决
  • 华为OD机试2025C卷-相对开音节[100分]( Java _ Python3 _ C++ _ C语言 _ JsNode _ Go)实现100%通过率
  • 【前端分享】封神级React图片预览组件!7KB超轻量,手势/动画/自定义全拿捏!
  • PEO10500-b-PMMA18000聚氧乙烯-b-聚甲基丙烯酸甲酯PEO-PMMA
  • 探秘大模型训练数据:Claude、ChatGPT 等的数据从何而来?能否实现公平交易?
  • WordPress+WooCommerce大型商城解决方案
  • A.每日一题:1344. 时钟指针的夹角
  • 【2026】超详细中望CAD机械版2026安装保姆级教程,永久免费使用,机械设计环境配置指南,看完这一篇就够了
  • 冯·诺依曼结构和哈佛结构
  • 激光焊接不只是替掉了钎焊——它正在重新定义液冷板能长什么样
  • TensorFlow 学习
  • Linux命令-pwd(打印当前工作目录)
  • 三分钟带你认识有机溶质转运蛋白(OST)家族
  • AI引发存储危机,苹果Mac、iPad涨价,iPhone 18会跟进吗?
  • 服务周到的牙科诊所如何挑选
  • RocketMQ 从0到1