
网站突然变慢、页面加载要十几秒、后台操作频繁卡住,很多时候根因不在前端,而在数据库:几条执行缓慢的 SQL 把连接池占满,后续请求全部排队。这篇文章解决的是”不知道哪条 SQL 在拖慢网站”的问题——帮助你通过开启 MySQL(一种常用的关系型数据库)慢查询日志,把拖垮网站的慢 SQL 一条条揪出来,并完成从定位到修复验证的完整闭环。整个流程在 VPS(虚拟专用服务器)或独立服务器上都可以直接操作,不需要额外付费工具。
一、先确认慢查询日志有没有开启
MySQL 默认可能没有开启慢查询日志,日志不开启就永远不知道问题在哪。登录数据库后先检查当前状态:
SHOW VARIABLES LIKE 'slow_query_log'; SHOW VARIABLES LIKE 'slow_query_log_file'; SHOW VARIABLES LIKE 'long_query_time';
如果 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 = ON -- long_query_time = 1 -- slow_query_log_file = /var/log/mysql/slow.log
long_query_time 是关键参数:执行时间超过这个阈值(单位秒)的 SQL 会被记入慢日志。第一次排查建议设为 1 秒,先抓出最明显的慢查询;如果记录太多,再降到 0.5 秒缩小范围。log_queries_not_using_indexes 开启后,没有走索引的查询即使没超时也会被记录,很适合发现”单次不慢但全表扫描”的隐患查询。设置完成后,随便执行一条已知较慢的查询,确认 slow_query_log_file 指向的文件里出现了记录,验证日志确实在工作。
三、制造或等待慢查询出现
日志开启后,需要让慢 SQL 真实发生才有内容可分析。两种方式都能拿到样本:
- 直接复现:在业务低峰期,把用户反馈最慢的那个页面打开几次,或者用
mysqlslap之类工具对疑似接口压测,触发慢查询写入日志。 - 线上等待:保持日志开启跑几个小时,覆盖一次完整的业务高峰,这样抓到的样本更接近真实负载。
样本量不用贪多,通常几十条记录就足够定位主要问题。排查期间如果同时发现服务器整体负载异常,CPU 或磁盘 IO 也可能是共犯,可以配合 网站优化专栏一起看。日志文件里每条记录包含执行时间、锁等待时间、返回行数、扫描行数和完整 SQL 文本,其中”扫描行数远大于返回行数”是缺索引最典型的信号——比如扫描了 40 万行只为了返回 10 条数据。
四、聚合分析:从几百条记录里找出元凶
慢日志是按时间顺序逐条追加的,重复查询会刷屏。直接翻文件效率很低,用 MySQL 自带的 mysqldumpslow 做聚合统计更快:
# 按总耗时排序,取最慢的前 10 条 mysqldumpslow -s t -t 10 /var/log/mysql/slow.log # 按出现次数排序,找出执行最频繁的查询 mysqldumpslow -s c -t 10 /var/log/mysql/slow.log
聚合结果会自动把具体参数替换成占位符,相同模式的查询合并成一条统计。实践中通常先看 -s c(次数)的榜单:一条单次 0.8 秒的查询如果每秒执行 20 次,对数据库的伤害远大于一条每天跑一次的 5 秒查询。找出总耗时贡献最大的 1-3 类查询,就是拖垮网站的元凶。

五、确认根因并修复问题 SQL
拿到具体 SQL 后,用 EXPLAIN(MySQL 的执行计划分析命令)看它到底怎么执行,判断是缺索引、写法问题还是数据量问题:
EXPLAIN SELECT * FROM orders WHERE customer_email = 'demo@example.com' ORDER BY created_at DESC;
重点看三个信号:type 为 ALL 表示全表扫描,key 为 NULL 表示没命中索引,rows 数值过大表示扫描范围失控。对应修复动作通常是加一个覆盖 WHERE 和 ORDER BY 条件的联合索引,例如 ALTER TABLE orders ADD INDEX idx_email_created (customer_email, created_at);。加索引前先评估表的写入频率,避免在生产高峰期执行长时间锁表的操作。拿到 SQL 之后怎么看执行计划、怎么验证索引是否命中,可以参考这篇 MySQL 慢查询日志分析实战,本文不再展开 EXPLAIN 的每个字段。如果你在管理 WordPress 网站,数据库层面的优化还可以配合对象缓存一起做,具体可以参考这篇 WordPress 数据库优化与缓存指南。
六、修复后必须验证效果
修复动作完成后不能直接收工,要回到数据验证三个问题:慢日志里还有没有这类查询、页面耗时是否下降、有没有连带拖慢其他查询。
- 重新打开之前报慢的页面,用浏览器开发者工具或
curl -w "%{time_total}"对比修复前后的总耗时,正常应有明显下降。 - 观察
SHOW GLOBAL STATUS LIKE 'Slow_queries';的计数增长速度,修复后新增慢查询次数应大幅减少。 - 保持慢日志开启至少一个业务高峰周期,确认聚合榜单前列不再出现同一类查询。
如果加了索引后 EXPLAIN 仍显示全表扫描,可能是统计信息过期,执行 ANALYZE TABLE 表名; 更新后再试。修复验证不能只看单次结果,至少覆盖一轮完整业务流量才算可靠。

总结与行动建议
MySQL 慢查询定位的完整路径是:开启慢查询日志 → 设置合理的 long_query_time 阈值 → 收集真实负载下的慢查询样本 → 用 mysqldumpslow 聚合找出高频元凶 → EXPLAIN 确认根因并修复 → 回到线上验证效果。整个过程不依赖收费工具,一台普通的 VPS 就能完成。我们的建议是:如果你的网站最近频繁变慢,今天就先把慢日志开起来,跑满一个业务高峰再分析;对于运行在 Hostease VPS 或独立服务器上的 WordPress 站点,数据库与网站在同一台机器时更要定期做这项巡检,避免慢 SQL 积累到拖垮整站才发现。如果你需要进一步优化网站整体响应速度,还可以参考这篇 网站性能与 TTFB 优化,把数据库层和前端加载一起治理。