MySQL 慢查询排查与优化(慢日志 / EXPLAIN / 索引)
2026-08-11 01:32:30 # 数据库

查询变慢是 MySQL 最常见的性能投诉。定位慢查询的关键,是“先有日志,再分析计划,最后加索引”。

一、开启慢查询日志

my.cnf 中:

1
2
3
4
slow_query_log = ON
slow_query_log_file = /var/log/mysql/slow.log
long_query_time = 1 # 超过 1 秒记为慢查询
log_queries_not_using_indexes = ON # 记录未走索引的 SQL(可选)

重启或 SET GLOBAL slow_query_log=ON; 生效。

二、分析慢日志

1
2
3
mysqldumpslow -s t -t 10 /var/log/mysql/slow.log   # 按总耗时取 Top10
# 更强大:Percona Toolkit
pt-query-digest /var/log/mysql/slow.log | less

三、用 EXPLAIN 看执行计划

1
EXPLAIN SELECT * FROM orders WHERE user_id=10 AND status=1\G

重点看四列:

  • type:从 ALL(全表扫描)到 const(常量),越靠前越差;目标是 ref/range/eq_ref
  • key:实际使用的索引,NULL 表示没走索引。
  • rows:扫描行数,越大越慢。
  • ExtraUsing filesort / Using temporary 都是性能红灯。

四、索引优化要点

  • 遵循最左前缀原则:联合索引 (a,b,c) 才能命中 WHERE a=? AND b=?
  • 尽量覆盖索引:查询字段都在索引里,避免回表。
  • 不要对列做函数包裹:WHERE DATE(create_time)=... 会让索引失效,改成范围查询。
  • 区分度低的列(如性别)不适合单独建索引。

五、一个典型案例

某接口偶发 3 秒超时,pt-query-digest 抓到一条 SELECT ... WHERE order_no=?EXPLAIN 显示 type=ALL。加上 ALTER TABLE orders ADD INDEX idx_order_no(order_no); 后,查询降到 1 毫秒。

小结

慢查询排查 = 慢日志定位 SQL → EXPLAIN 看计划 → 补/调索引。索引建错比不建更糟,务必结合执行计划。