服务器 mysql 慢查询如何排查 精华

chinaz
chinaz 初级会员超兽战士
发布于 2026-10-07 21:02 ·3 浏览 ·0 回复

学完这篇,你能独立定位一条 MySQL 慢查询卡在哪一步,并给出可落地的优化动作。

第一步:确认慢查询日志开着,并拿到日志文件

MySQL 默认不记录慢查询,先确认状态。登录后执行:

SHOW VARIABLES LIKE 'slow_query_log';
SHOW VARIABLES LIKE 'long_query_time';
SHOW VARIABLES LIKE 'slow_query_log_file';

如果 slow_query_log 是 OFF,临时开启(重启失效):

SET GLOBAL slow_query_log = ON;
SET GLOBAL long_query_time = 1;
SET GLOBAL log_queries_not_using_indexes = ON;

永久生效要改配置文件 my.cnf,在 [mysqld] 段下加:

slow_query_log = 1
slow_query_log_file = /var/lib/mysql/slow.log
long_query_time = 1
log_queries_not_using_indexes = 1

改完 systemctl restart mysqld(或 service mysql restart)。做完这一步,你能在 slow_query_log_file 指定的路径看到慢查询记录。

注意:long_query_time 单位是秒,可以写小数如 0.5;SET GLOBAL 只影响新连接,已有连接仍用旧值。生产库开 log_queries_not_using_indexes 会写入大量日志,建议只在排查期临时开。

第二步:从日志里找出「最值得优化」的那几条

日志会很长,别一条条看。两种工具:

mysqldumpslow(MySQL 自带):

mysqldumpslow -s t -t 10 /var/lib/mysql/slow.log

-s t 按总耗时排序,-t 10 取前 10 条。还可以 -s c 按出现次数排序,找高频慢 SQL。

pt-query-digest(Percona Toolkit,分析更细):

pt-query-digest /var/lib/mysql/slow.log

输出里有 Query ID、Response time 占比、Rows examine 与 Rows sent 的比例,比例悬殊说明扫了太多行、索引没用上。做完这一步,你手上应该只剩 1~3 条待分析的 SQL。

第三步:用 EXPLAIN 看执行计划

拿到具体 SQL 后,在它前面加 EXPLAIN:

EXPLAIN SELECT * FROM orders WHERE user_id = 10086 AND status = 1;

重点看四个字段:

  • type:出现 ALL 是全表扫描,index 是全索引扫描,都不理想;ref、range、eq_ref 才算正常。
  • key:实际用的索引,为 NULL 说明没走索引。
  • rows:预估扫描行数,越大越危险。
  • Extra:出现 Using filesort(额外排序)、Using temporary(临时表)通常就是性能杀手。

MySQL 8.0 可以用 EXPLAIN ANALYZE SELECT ... 看真实执行耗时和实际行数,和预估行数对比能发现统计信息偏差。

注意:EXPLAIN ANALYZE 会真正执行语句,在几十万行以上的表上跑,先加 LIMIT 或到从库执行。

第四步:对照索引做优化

用 SHOW INDEX FROM orders; 看现有索引。常见问题与动作:

  1. 没索引:对 WHERE、JOIN ON、ORDER BY 涉及的列建索引,例如 ALTER TABLE orders ADD INDEX idx_user_status (user_id, status);
  2. 组合索引顺序不对:遵循最左前缀原则,把区分度高(唯一值多)的列放前面,SHOW INDEX 里 Cardinality 越大越靠前。
  3. 索引失效:WHERE 里对索引列做了函数运算(如 DATE(created_at) = '2024-01-01')、隐式类型转换(字符串列传数字)、LIKE '%xx' 前置通配,都会让索引失效,改写 SQL 而不是加索引。
  4. 回表太多:查询只需要少数几列时,把这几列加进索引做覆盖索引,让 Extra 出现 Using index。

第五步:确认是不是被锁或并发拖慢的

如果单条 SQL 单独跑很快,线上却慢,查实时状态:

SHOW FULL PROCESSLIST;
SELECT * FROM sys.innodb_lock_waits;
SHOW ENGINE INNODB STATUS\G

State 长时间停在 Waiting for table metadata lock 或 Sending data,说明瓶颈在锁等待或大量数据读取,不是索引问题。

小结

  • 排查链路是:开慢日志 → 聚合排序找重点 → EXPLAIN 看执行计划 → 对照索引改 SQL/加索引 → 必要时查锁与并发。
  • 优先看 type、key、rows、Extra 四个字段,别通读日志。
  • 索引优化遵守最左前缀,注意函数运算和隐式转换导致的失效。
  • EXPLAIN ANALYZE 会执行语句,生产环境慎用,可先上从库。
版权声明:本文来自 GJ站长论坛《服务器 mysql 慢查询如何排查》
原文链接:https://www.gj0.com/thread-539.html
转载请注明出处并保留本声明;内容仅代表作者观点,与本站立场无关。若本文涉嫌侵权,请联系本站处理。
他们都看过 1 人浏览过
GJ论坛站长

全部回复 0

还没有回复,来抢沙发~