查询优化
一、查询优化的第一性原理(原理层 · 稳定)
1.1 查询性能的本质公式
查询性能 ≠ SQL 执行速度查询性能 = 数据访问成本 + 计算成本 + 协调成本
这是所有数据库、所有版本、所有引擎都成立的第一性原理。
| 成本类型 | 本质解释 | 常见表现 |
|---|---|---|
| 数据访问成本 | 访问了多少数据 | 扫描行数、回表、随机 IO |
| 计算成本 | 对数据做了多少处理 | 排序、聚合、表达式计算 |
| 协调成本 | 多对象协作的代价 | 锁等待、JOIN、中间结果 |
查询优化的全部目标:👉 用尽可能低的代价,得到足够准确的结果。
1.2 一个更底层的不变量
性能问题,本质是“无效数据的代价”
- 扫描但未返回的数据
- 排序但最终被丢弃的数据
- JOIN 过程中生成但未使用的中间结果
- 为分页而遍历的历史数据
优化 ≠ 更快执行优化 = 更少做无意义的工作
二、查询优化的三层认知模型(结构层 · 稳定)
查询优化├── 逻辑层:你“想要什么”├── 执行层:数据库“如何做”└── 物理层:数据“如何存”这是理解所有优化手段的认知骨架。
三、逻辑层优化:减少“想要的东西”(抽象层)
3.1 结果集裁剪原则(最重要)
越早裁剪,越低成本
| 裁剪方式 | 原理 |
|---|---|
| 列裁剪 | 减少数据传输与内存占用 |
| 行裁剪 | 减少扫描、排序、JOIN |
| 条件前推 | 减少中间结果规模 |
设计原则:
- SELECT 只返回必要字段
- WHERE 越精确越好
- LIMIT 是一种“成本控制器”
3.2 大查询拆分原则
不要一次性处理峰值负载
将一个“资源洪峰”拆解为多个“小波峰”:
- 降低锁冲突
- 平滑 IO 压力
- 提高系统整体可预测性
👉 本质是 时间换空间、稳定性换复杂度
四、执行层优化:减少“如何做”的成本(架构层)
4.1 MySQL 执行架构(稳定认知)
SQL → 解析(Parser) → 预处理(Preprocessor) → 优化(Optimizer) → 执行(Executor) → 存储引擎(Storage Engine)关键认知:
- 优化器是**基于统计假设的成本计算器**
- 执行引擎只是“计划的执行者”
- 存储引擎决定 IO 行为
4.2 扫描行数:执行层最重要指标
扫描行数 ≫ 返回行数 = 性能风险
衡量手段:
- 慢查询日志(rows_examined)
- EXPLAIN 预估行数
理想状态:
扫描行数 ≈ 返回行数4.3 覆盖索引的本质
避免回表 = 避免随机 IO
覆盖索引不是“技巧”,而是一种执行路径优化:
- 索引即数据
- 在有序结构中完成计算
- 减少存储层交互
4.4 JOIN 的本质代价
JOIN 是中间结果放大器
JOIN 的真实成本来自:
- 驱动顺序
- 中间结果规模
- 条件是否可下推
设计原则:
- 小表驱动大表
- JOIN 条件必须可索引
- 能拆就拆,能缓存就缓存
五、物理层优化:减少“数据如何存”的摩擦(实现层)
5.1 排序的真实成本模型
排序不是比较,而是搬运数据
- filesort ≠ 文件排序
- 临时表 ≠ 内存安全
排序代价由三部分构成:
- 数据量
- 数据宽度
- 临时空间
核心原则:
- 利用索引的有序性
- 用 LIMIT 控制排序规模
5.2 临时表与内存边界
所有“内存操作”都有溢出成本
- 内存临时表 → 磁盘临时表
- 小参数 → 多次 IO
- 大参数 → 内存竞争
👉 本质是 资源配额管理问题
六、优化器:能力、边界与理性使用(哲学层)
6.1 优化器的工作假设
优化器依赖:
- 统计信息
- 基数估算
- 成本模型
但它不知道业务真实分布。
6.2 为什么不要迷信优化器提示
Hint 是“冻结假设”
- 数据会变
- MySQL 会演进
- 旧假设可能变成性能陷阱
设计哲学:
只有在“结构性误判”时,才干预优化器
七、典型查询模式的本质分析(模式层)
7.1 COUNT 的哲学
COUNT 的成本 = 遍历成本
- COUNT(*) ≠ 免费
- 精确统计是昂贵操作
架构性解法:
- 汇总表
- 近似值
- 外部缓存
7.2 分页的核心矛盾
OFFSET 的本质是“丢弃成本”
- OFFSET 越大,丢弃越多
- 本质是线性扫描
正确思路:
- 基于游标
- 基于边界值
- 基于连续性假设
7.3 IN / 子查询的风险本质
优化器无法准确评估“组合爆炸”
- IN 参数过多
- 子查询结果集不确定
👉 本质是 估算失败导致路径错误
八、查询优化的决策框架(方法论)
查询慢├─ 数据访问多?│ ├─ 索引设计│ ├─ 条件裁剪│ └─ 数据分布├─ 中间结果大?│ ├─ JOIN│ ├─ 排序│ └─ 分组├─ 协调成本高?│ ├─ 锁│ ├─ 事务│ └─ 网络└─ 架构问题? ├─ 缓存 ├─ 汇总 └─ 异步九、演进视角:哪些知识会过期,哪些不会
会过期的
- 参数调优经验
- 某版本优化器缺陷
- 特定 Hint 用法
不会过期的
- 减少扫描行数
- 减少中间结果
- 提前裁剪数据
- 用结构换性能
关联内容(自动生成)
- [/中间件/数据库/数据库优化.html](/中间件/数据库/数据库优化.html) 数据库优化涵盖更广泛的优化策略,包括索引模型、查询优化、分布式治理等,与MySQL查询优化形成互补
- [/中间件/数据库/索引.html](/中间件/数据库/索引.html) 索引技术是查询优化的核心基础,详细介绍了B+树、哈希索引等数据结构及优化策略
- [/数据技术/检索技术.html](/数据技术/检索技术.html) 检索技术与查询优化在索引结构、查询性能优化方面有诸多相通之处
- [/中间件/数据库/ElasticSearch.html](/中间件/数据库/ElasticSearch.html) ES的查询优化与MySQL查询优化在性能调优、索引策略等方面可作对比参考
- [/数据技术/数据建模.html](/数据技术/数据建模.html) 数据建模中的物理优化能力与查询优化密切相关,涉及索引、分区等策略
- [/软件工程/性能工程/性能优化.html](/软件工程/性能工程/性能优化.html) 系统性性能优化方法论为数据库查询优化提供了更宏观的视角
- [/编程语言/JAVA/高级/JDBC.html](/编程语言/JAVA/高级/JDBC.html) JDBC与数据库交互的优化是查询优化在应用侧的延伸,涉及连接管理和SQL执行优化
- [/中间件/数据库/PostgreSQL.html](/中间件/数据库/PostgreSQL.html) PostgreSQL的查询优化策略与MySQL可作对比学习,加深对数据库优化原理的理解
- [/软件工程/架构/系统设计/缓存.html](/软件工程/架构/系统设计/缓存.html) 缓存策略是查询优化的重要组成部分,与数据库查询优化形成完整的数据访问优化体系
- [/中间件/数据库/数据库系统/事务管理/事务.html](/中间件/数据库/数据库系统/事务管理/事务.html) 事务管理与查询优化密切相关,特别是在并发控制和锁策略方面