需先开启慢查询日志(slow_query_log=on)、设阈值(long_query_time=0.5~1)、指定路径,并关闭log_queries_not_using_indexes;再用explain分析type、key、rows、extra四列,重点关注全表扫描、索引失效、文件排序及临时表问题。

怎么定位慢查询SQL
MySQL默认不记录慢查询,得先打开慢查询日志开关,并设好阈值。否则你根本不知道哪条SQL拖慢了整体响应。
关键配置项:slow_query_log(设为ON)、long_query_time(比如设成1秒)、slow_query_log_file(指定日志路径)。注意:MySQL 5.7+ 默认只记录没走索引的查询,需额外设log_queries_not_using_indexes=OFF避免干扰。
- 线上建议
long_query_time设为0.5或1,太低会导致日志爆炸 - 日志文件权限要让MySQL进程可写,否则开启失败但无明显报错
- 用
SHOW VARIABLES LIKE 'slow_query_log%'确认是否生效,别只改配置不重启/重载
EXPLAIN看执行计划时重点盯什么
EXPLAIN输出里真正影响性能的是type、key、rows、Extra这四列,其他字段多数是辅助信息。
-
type:从好到坏是const≈eq_ref>ref>range>index>ALL;出现ALL基本等于全表扫描 -
key为空说明没走索引,得查WHERE条件字段有没有对应索引,或索引是否被隐式转换失效(比如对varchar字段用数字查询) -
rows是MySQL预估扫描行数,如果远大于实际结果集,说明统计信息过期,可运行ANALYZE TABLE更新 -
Extra里出现Using filesort或Using temporary要警惕,尤其是二者同时出现,大概率需要优化排序或关联方式
ORDER BY和GROUP BY为什么容易慢
这两个操作若无法利用索引完成,MySQL会强制使用临时表+文件排序,I/O和内存开销陡增。
例如SELECT * FROM orders WHERE status = 1 ORDER BY create_time DESC,即使status有索引,create_time没包含在索引里,就无法避免Using filesort。
- 复合索引顺序很重要:
WHERE条件字段在前,ORDER BY字段紧随其后,比如(status, create_time) -
GROUP BY同理,优先复用WHERE索引,再追加分组字段;如果带聚合函数又没索引,可能触发Using temporary - 避免
SELECT *+ORDER BY,只查必要字段能减少排序数据量
JOIN太多或字段类型不一致导致隐式转换
多表JOIN本身不必然慢,但一旦驱动表选错、连接字段类型不匹配,就会让索引完全失效。
典型例子:user.id是BIGINT,order.user_id是VARCHAR,哪怕加了索引,MySQL也会把user.id转成字符串去比对——索引失效,变全表扫描。
- 用
SHOW CREATE TABLE确认关联字段类型、长度、字符集是否严格一致 - 小表驱动大表原则依然有效,但5.7+优化器会自动判断,不过复杂JOIN下仍建议用
STRAIGHT_JOIN强制顺序 - 超过3张表JOIN要考虑是否真有必要,很多时候应用层拆成2次查询反而更快、更可控
慢查询排查不是单点动作,而是“日志抓取 → EXPLAIN验证 → 索引调整 → 再压测”的闭环。最容易被忽略的是统计信息过期和字符集隐式转换——它们不会报错,但会让所有索引形同虚设。











