MySQL 慢查询日志分析实战:从 EXPLAIN 到索引回归验证

MySQL 慢查询日志分析封面

这篇指南帮助你掌握 MySQL 慢查询分析的完整闭环:开启慢查询日志、用 EXPLAIN 看懂执行计划、判断是否缺索引、加索引后做回归验证。数据库慢查询不是只看一条 SQL 慢不慢,而是要确认根因、验证修复效果、防止修了这一条却引入新的性能问题。

如果你的站点已经做过 WordPress 数据库清理,但仍然出现页面加载慢、后台操作卡顿,下一步就该排查 MySQL(一种关系型数据库)的慢查询。Hostease 中文博客里有一篇 WordPress 数据库优化指南讲了冗余数据清理,本文则聚焦于查询本身:怎么定位慢 SQL、怎么判断索引是否有效、怎么验证修复没有副作用。

一、开启慢查询日志

MySQL 默认可能未开启慢查询日志。先用以下命令确认当前状态,再按需开启。慢查询日志会记录所有执行时间超过阈值的 SQL 语句,是定位性能问题的第一手数据。

-- 查看慢查询日志状态
SHOW VARIABLES LIKE 'slow_query_log%';
SHOW VARIABLES LIKE 'long_query_time';

-- 临时开启(重启后失效)
SET GLOBAL slow_query_log = 'ON';
SET GLOBAL long_query_time = 1;
SET GLOBAL slow_query_log_file = '/var/log/mysql/slow.log';

long_query_time 建议先设为 1 秒抓明显慢的查询,确认后再逐步降到 0.5 秒甚至 0.1 秒抓更细的问题。生产环境长期开启慢查询日志会有轻微写入开销,但如果磁盘空间充足,建议保持开启并定期轮转清理。

二、从慢日志中提取热点查询

慢查询日志可能包含大量重复语句。用 mysqldumpslowpt-query-digest 聚合统计,找出出现频率最高或平均耗时最长的查询。

 # 按总耗时排序,取前 10
mysqldumpslow -s t -t 10 /var/log/mysql/slow.log

 # 或用 pt-query-digest 做更详细的分析
pt-query-digest /var/log/mysql/slow.log | head -40

重点关注两类查询:一是单次执行很慢(如超过 2 秒),二是执行次数很多且每次都慢。前者可能是缺索引或全表扫描,后者可能是缓存失效后的集中冲击。把热点查询的 SQL 文本记下来,进入下一步用 EXPLAIN 分析。

三、用 EXPLAIN 看懂执行计划

EXPLAIN 是 MySQL 提供的执行计划分析工具,它不会真正执行查询,而是告诉你 MySQL 打算怎么执行。重点关注以下字段:

  • type:访问类型。ALL 表示全表扫描,index 表示扫描整个索引树,range 表示索引范围扫描,ref 表示索引等值查找。ALL 和 index 通常是需要优化的信号。
  • key:实际使用的索引。如果为 NULL,说明没有命中索引。
  • rows:预估扫描行数。这个值越大,查询越可能慢。
  • Extra:附加信息。出现 Using filesort 或 Using temporary 通常意味着需要额外排序或临时表,值得关注。
EXPLAIN SELECT * FROM wp_posts WHERE post_status = 'publish' AND post_type = 'post' ORDER BY post_date DESC;

EXPLAIN 执行计划关键字段

如果 EXPLAIN 显示 type 为 ALL、rows 为几十万、Extra 出现 Using filesort,基本可以确认这条查询在全表扫描后还做了排序,是典型的慢查询根因。

四、判断是否需要加索引

加索引前要确认查询的 WHERE、JOIN 和 ORDER BY 条件。以上面查询为例,post_statuspost_type 是过滤条件,post_date 是排序条件。可以建一个联合索引覆盖过滤和排序。

-- 加联合索引前先确认不会锁表太久
ALTER TABLE wp_posts ADD INDEX idx_status_type_date (post_status, post_type, post_date);

加索引不是越多越好。每个索引都有写入开销和存储成本。如果一张表已经有 5 个以上索引,再加之前要评估收益。对于写多读少的表,索引过多会拖慢 INSERT 和 UPDATE。如果你做过 WordPress 安全加固,其中修改登录限制或防火墙规则不会影响数据库索引,但插件频繁写入日志表时,要检查日志表是否建了过多索引。

五、索引回归验证

加索引后必须重新跑 EXPLAIN 确认执行计划变化,并用相同查询验证耗时是否下降。这一步很多人省略,结果加了索引却没有命中,或者命中了但整体没变快。

-- 重新 EXPLAIN 确认索引命中
EXPLAIN SELECT * FROM wp_posts WHERE post_status = 'publish' AND post_type = 'post' ORDER BY post_date DESC;

-- 对比修复前后执行时间
SET profiling = 1;
SELECT * FROM wp_posts WHERE post_status = 'publish' AND post_type = 'post' ORDER BY post_date DESC;
SHOW PROFILE;

验证时注意三点:第一,type 应从 ALL 变成 ref 或 range;第二,rows 应大幅下降;第三,Extra 中的 Using filesort 可能消失。如果索引加了但 EXPLAIN 仍显示 ALL,可能是统计信息过期,需要 ANALYZE TABLE 更新。如果排序仍然 Using filesort,说明索引顺序与 ORDER BY 方向不一致。

六、防止修复引入新问题

加索引后除了验证目标查询变快,还要监控是否有其他查询变慢。联合索引的列顺序会影响哪些查询能命中。比如 (post_status, post_type, post_date) 这个索引,单独按 post_date 查询时无法命中,因为联合索引遵循最左前缀原则。

查询条件 是否命中索引 原因
post_status + post_type + post_date 命中 完整匹配联合索引
post_status + post_type 命中 最左前缀匹配
post_type + post_date 不命中 跳过了 post_status
post_date only 不命中 不满足最左前缀

所以加索引后建议在测试环境跑一遍全量查询回归,确认没有其他查询因索引变化而变慢。如果生产环境无法停机测试,可以在从库上验证,或选择低峰期操作并准备好回滚命令。慢查询治理通常需要和缓存策略配合:索引解决的是数据库本身的查询效率,而缓存减少的是查询次数。如果你还没有缓存层,可以参考 多层缓存架构把高频查询的结果缓存到 Redis 或内存,进一步降低数据库压力。如果你在 VPS 入侵应急处理后需要排查数据库异常,慢查询日志也能帮助确认是否有异常查询被注入。

索引回归验证流程

总结

MySQL 慢查询分析的完整闭环是:开启慢查询日志 → 用 mysqldumpslow 聚合热点 → 用 EXPLAIN 看执行计划 → 判断索引缺口 → 加索引后重新 EXPLAIN 验证 → 监控是否引入新问题。关键是不要只看一条 SQL 慢就加索引,要确认执行计划变化并做回归验证。对于 Hostease 这类面向中文用户的 [VPS](https://cn.hostease.com/vps/) 或[独立服务器](https://cn.hostease.com/dedicated-server/)环境,数据库慢查询直接影响 WordPress 页面加载速度,定期用这套流程排查可以避免性能问题积累到影响用户体验。

发表评论