SQL性能调优需同步验证查询执行路径、数据分布、统计信息和存储引擎行为四层面;EXPLAIN关键看rows(估算扫描行数)、key(实际索引名,NULL可能因覆盖索引)、Extra中Using filesort/Using temporary;复合索引须按等值→范围→排序顺序设计;JOIN字段禁用函数或类型转换;统计信息不准须手动ANALYZE TABLE。

SQL 性能调优不是靠猜,也不是堆索引就能解决的;它需要从查询执行路径、数据分布、统计信息和存储引擎行为四个层面同步验证。跳过任一环节,都可能把 WHERE 条件优化了,却让 JOIN 变成全表扫描。
看懂 EXPLAIN 输出里真正关键的三列
EXPLAIN 不是只看 type 是不是 ref 或 range,重点在三处:
-
rows:MySQL 估算的扫描行数,如果远大于实际匹配行数(比如估算 10 万,实际只返回 5 行),说明统计信息过期或索引选择错误 -
key:实际用到的索引名,为空不等于没走索引——可能是用了覆盖索引但key显示为NULL(如SELECT id FROM t WHERE status=1走了status索引且该索引包含id) -
Extra中的Using filesort或Using temporary:意味着排序或分组没走索引,即使WHERE很快,整体也会慢
复合索引字段顺序不能只按 WHERE 出现顺序排
字段顺序必须匹配“等值条件 → 最左前缀 → 范围/排序字段”这个执行逻辑:
- 等值条件(
=、IN)字段放最左,且优先放区分度高的(如user_id比status更适合放前面) - 范围条件(
>、BETWEEN)只能放最后一位,它后面的字段无法被索引下推 -
ORDER BY字段如果要避免Using filesort,必须紧接在等值字段之后,且方向一致(如INDEX(a,b,c)支持WHERE a=1 ORDER BY b,c,但不支持ORDER BY c,b)
别在 JOIN 字段上加函数或类型转换
哪怕只是 CAST(user_id AS CHAR) 或 LOWER(email),都会让关联字段失效索引:
- MySQL 8.0+ 对部分函数(如
JSON_EXTRACT)支持函数索引,但普通字符串函数不行 - 常见陷阱:
ON a.id = b.user_id + 0(隐式转数字)、ON a.code = UPPER(b.code)(大小写不一致) - 修复方式:统一字段类型、提前计算好值存入冗余列、或用生成列(
GENERATED COLUMN)加索引
统计信息不准会直接误导优化器选错执行计划
尤其在大表批量导入/删除后,ANALYZE TABLE 不是可选项,是必做动作:
- 默认采样率低(
innodb_stats_sample_pages=20),小样本遇上倾斜数据(如 95% 的status=1,5% 的status=2),优化器会误判status=2也很快 - 手动更新:运行
ANALYZE TABLE orders;,或调高采样页数(SET GLOBAL innodb_stats_sample_pages = 100;) - 注意:InnoDB 的统计信息是后台异步更新的,
SHOW INDEX里的Cardinality值可能滞后几分钟
最常被忽略的是:同一个 SQL 在不同数据量级下,最优索引可能完全相反;没有银弹索引,只有匹配当前数据分布和查询模式的索引。











