MySQL 优化器除了 自动将 WHERE 条件前置(谓词下推,Predicate Pushdown) 之外,还会进行许多其他关键优化,以提高查询性能。以下是主要的优化策略及其示例:
1. 查询重写(Query Rewriting)
优化器会 重写 SQL,使其更高效,即便 SQL 写法不同,最终执行计划可能相同。
示例优化
-
IN → EXISTS / JOIN 转换
sql-- 原始语句 SELECT * FROM users WHERE id IN (SELECT user_id FROM orders); -- 可能被优化为 SELECT users.* FROM users JOIN orders ON users.id = orders.user_id; -
OR 合并优化
sql-- 原始语句 SELECT * FROM users WHERE age > 20 OR salary > 5000; -- 可能拆分成两个 Range Scan 并合并
2. 索引优化
优化器会 智能选择最佳索引 ,甚至 动态调整索引使用策略。
示例优化
-
覆盖索引(Covering Index)
- 如果可以,优化器会直接从索引读取数据,避免回表(减少 I/O)。
sqlSELECT id, name FROM users WHERE age = 25; -- 如果 (age, id, name) 构成覆盖索引,就不读表数据 -
Index Skip Scan(MySQL 8.0+)
- 对复合索引
(a, b),即使a未指定,也能利用b的部分扫描。
- 对复合索引
-
Multi-Range Read (MRR)
- 先收集 所有满足 WHERE 条件的 id,再按主键排序读取数据(减少随机 I/O)。
-
Index Condition Pushdown (ICP, 索引条件下推)
- 让存储引擎 在索引层过滤数据 (减少回表次数)。
sql-- 复合索引 (name, age) SELECT * FROM users WHERE name LIKE '张%' AND age > 20; -- ICP 让存储引擎直接过滤 age > 20,避免回表
3. 连接优化(Join Optimizations)
优化器会 调整 JOIN 顺序、方式,减少计算量。
示例优化
-
JOIN 顺序优化
- 小表优先 JOIN(减少中间结果)。
sqlSELECT * FROM large_table JOIN small_table ON ...; -- 优化器可能会自动先处理 small_table -
使用
Batched Key Access (BKA)- 减少 JOIN 时的随机 I/O(结合 MRR)。
-
Hash Join / Nested Loop Join 选择
- MySQL 8.0+ 支持 Hash Join(适合无索引大表 JOIN 时)。
-
子查询优化(Subquery Materialization)
IN (...)子查询可能被 物化(临时表缓存),避免重复计算。
-
外连接转内连接(OUTER JOIN → INNER JOIN)
sqlSELECT * FROM users LEFT JOIN orders ON users.id = orders.user_id WHERE orders.user_id IS NOT NULL; -- 优化器可能自动转成 INNER JOIN
4. 聚合和分组优化
-
Loose Index Scan(松散索引扫描)
-
优化
GROUP BY,避免全表扫描:sqlSELECT category, COUNT(*) FROM products GROUP BY category; -- 如果 (category) 有索引,可能直接扫描索引而非全表
-
-
Using Temporary + Filesort → 直接索引排序
- MySQL 会尝试避免临时表排序,尽量使用索引。
sqlSELECT * FROM users WHERE age > 20 ORDER BY name; -- 如果 (age, name) 有索引,优化器会避免 Filesort
5. 数据访问优化
-
Buffer Pool 缓存
- 如果数据已经被缓存,优化器会 避免磁盘 I/O。
-
并行查询(MySQL 8.0+)
- 某些查询可能 并行执行 (如
COUNT(*))。
- 某些查询可能 并行执行 (如
-
Optimizer Hints 优化器提示
-
可手动指定索引、JOIN 顺序:
sqlSELECT /*+ INDEX(users idx_age) */ * FROM users WHERE age = 20;
-
6. 查询执行优化
-
延迟 JOIN(Delayed Join)
- 先过滤数据再 JOIN,减少中间结果集。
-
LIMIT 优化
sqlSELECT * FROM users LIMIT 10; -- MySQL 检测到 LIMIT 时,可能在索引扫描时直接返回 10 条 -
统计信息更新
- 优化器基于
ANALYZE TABLE的统计信息决定执行计划。
- 优化器基于
总结
| 优化技术 | 说明 |
|---|---|
| 谓词下推(Predicate Pushdown) | 尽早用 WHERE 减少数据量 |
| 覆盖索引(Covering Index) | 直接从索引读取数据,避免回表 |
| ICP(索引条件推送) | 存储引擎层过滤数据 |
| MRR / BKA | 优化 JOIN 的随机 I/O |
| Hash Join | 大表 JOIN 优化(MySQL 8.0+) |
| Loose Index Scan | 快速 GROUP BY |
| 子查询物化(Subquery Materialization) | 避免重复计算 IN 子查询 |
| 延迟 JOIN | 先过滤再连接 |
⚠️ 验证执行计划
用 EXPLAIN + EXPLAIN ANALYZE(MySQL 8.0+)查看查询如何优化!
如果有具体查询优化问题,可以提供 SQL,我可以帮你分析执行计划! 🚀