贝利信息

mysql执行SQL语句时的优化与查询重写

日期:2026-01-11 00:00 / 作者:P粉602998670
EXPLAIN 是优化慢查询的必要起点,它揭示索引使用、临时表、排序等真实执行细节;盲目改SQL易跑偏方向。

为什么 EXPLAIN 看起来没用,但必须先跑一遍

很多人在慢查询出现后直接改 SQL,跳过 EXPLAIN,结果优化方向完全跑偏。MySQL 的执行计划决定实际走哪个索引、是否临时表、是否排序、是否回表——这些无法靠肉眼判断。EXPLAIN 输出里的 type(如 ALLindexrange)、keyrowsExtra(尤其是 Using filesortUsing temporary)才是真实瓶颈信号。

JOIN 顺序不对,STRAIGHT_JOIN 有时比优化器更靠谱

MySQL 5.7+ 的优化器通常能选较优 JOIN 顺序,但在多表关联(尤其 4 张以上)、小表驱动大表逻辑明确、或存在复杂子查询嵌套时,它可能误判驱动表。此时强制顺序反而更快。

SELECT STRAIGHT_JOIN u.name, o.total
FROM users u
JOIN orders o ON u.id = o.user_id
WHERE u.created_at > '2025-01-01';

OR 拆成 UNION ALL 真的有用,但得看条件是否独立

WHERE 中含多个 OR 条件且涉及不同字段(如 status = 'draft' OR created_by = 123),MySQL 往往放弃使用索引,退化为全表扫描。拆成 UNION ALL 可让每个分支单独走索引。

SELECT id, title FROM posts WHERE status = 'published'
UNION ALL
SELECT id, title FROM posts WHERE author_id = 99;

子查询改写为 JOINLATERAL(MySQL 8.0.14+)更可控

相关子查询(如 SELECT * FROM orders WHERE user_id IN (SELECT id FROM users WHERE region = 'CN'))容易触发 N+1 扫描;而派生表(FROM (SELECT ...) AS t)若没被物化或无法下推条件,也可能低效。

真正棘手的不是语法改写,而是确认语义不变——比如 NULL 值处理、空结果集行为、重复键合并逻辑,这些地方一疏忽,数据就错了。