慢查询批量优化脚本解决数据库卡顿查询缓慢

数据库出现卡顿、页面加载变慢,背后往往藏着大量慢查询。
慢查询批量优化脚本能帮你自动收集耗时 SQL、定位低效语句并给出优化方向,避免逐个手动排查。
本文会带你从开启慢查询日志开始,写一个简单的批量分析脚本,完成一轮可验证的优化,整个过程不需要很深的基础,跟着命令敲就能跑起来。

先把慢查询日志打开

没有日志就等于没有体检报告。
以 MySQL 为例,先确认当前是否开启了慢查询记录:

SHOW VARIABLES LIKE 'slow_query_log%';
SHOW VARIABLES LIKE 'long_query_time';

如果 slow_query_logOFF,执行下面的 SQL 开启。
这里同时把阈值设为 1 秒,意思是执行时间超过 1 秒的 SQL 会被记录:

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

注意:修改 long_query_time 后,新连接才生效,建议直接在数据库配置文件 my.cnf(Linux)或 my.ini(Windows)里加上:

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

改完重启 MySQL 服务。
确认日志文件已经生成后,先跑一段时间(建议至少 15 分钟),积累足够样本再分析。

写一个批量慢查询分析脚本

拿到慢查询日志后,可以用脚本把耗时最高的 SQL 批量提取出来。
下面是一个 Python 脚本思路,适合日志格式为 # Time# Query_time 的 MySQL 慢日志:

import re
from collections import defaultdict

log_path = "/var/log/mysql/slow.log"
sql_stats = defaultdict(lambda: {"count": 0, "max_time": 0, "sql": ""})

with open(log_path, "r", encoding="utf-8", errors="ignore") as f:
    lines = f.readlines()

current_sql = []
exec_time = 0

for line in lines:
    if line.startswith("# Query_time:"):
        exec_time = float(line.split(":")[1].split()[0])
    elif line.strip() and not line.startswith("#"):
        current_sql.append(line.strip())
    elif line.startswith("#"):
        if current_sql:
            sql_text = " ".join(current_sql)[:200]
            sql_stats[sql_text]["count"] += 1
            sql_stats[sql_text]["max_time"] = max(sql_stats[sql_text]["max_time"], exec_time)
            sql_stats[sql_text]["sql"] = sql_text
        current_sql = []

# 按最大耗时排序,输出 TOP 10
sorted_sql = sorted(sql_stats.items(), key=lambda x: x[1]["max_time"], reverse=True)[:10]
for sql, info in sorted_sql:
    print(f"耗时: {info['max_time']}s | 次数: {info['count']}")
    print(f"SQL: {info['sql']}\n")

把脚本保存为 analyze_slow.py,运行:

python3 analyze_slow.py

脚本会打印出最耗时的 10 条 SQL。
对于临时救急,这个结果已经够用了。
如果想更全面,可以直接用 Percona Toolkit 里的 pt-query-digest

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

它能按平均耗时、总耗时、次数排序,并给出每一类 SQL 的样本和 EXPLAIN 建议,适合日志量较大的场景。

从分析报告里找出卡顿真凶

拿到 TOP SQL 后,先判断问题类型,再决定优化动作。
常见的有三类:

  • 全表扫描EXPLAIN 结果里 typeALL,说明没用上索引。优先看 WHERE 条件字段是否缺索引。
  • 索引失效:字段上用了函数、隐式类型转换,或者前导通配符 LIKE '%xx',都会导致索引失效。
  • 单次查询取数过多LIMIT 太大或没有 LIMIT,一次拉几十万行,数据库慢且网络传输也慢。

对确认需要加索引的语句,执行:

ALTER TABLE 表名 ADD INDEX idx_字段名 (字段名);

比如慢 SQL 里经常出现 WHERE user_id = 100 ORDER BY create_time DESC,可以建联合索引:

ALTER TABLE orders ADD INDEX idx_user_time (user_id, create_time);

不要一次性批量加很多索引,因为索引不是越多越好,写操作会变慢。
建议每次只加 1-2 个,观察后再继续。

执行优化后的效果验证

优化完不能只看日志里没有了,要量化前后变化。

先用 EXPLAIN 确认执行计划已经改变:

EXPLAIN SELECT * FROM orders WHERE user_id = 100 ORDER BY create_time DESC LIMIT 20;

理想情况下 typeALL 变成 refrangerows 明显减少。
然后直接看查询耗时,在你的客户端或命令行执行:

SELECT * FROM orders WHERE user_id = 100 ORDER BY create_time DESC LIMIT 20;

对比优化前的耗时。
如果要看整体效果,可以重新统计慢查询日志:清空旧日志,跑一段业务,再统计数量。

TRUNCATE TABLE mysql.slow_log;  -- 前提是已开启日志到表

或者直接删除慢日志文件后重建:

rm /var/log/mysql/slow.log
mysqladmin flush-logs

运行半个小时后,用 grep 统计新慢查询条数:

grep "Query_time" /var/log/mysql/slow.log | wc -l

数量明显下降,说明优化生效。
如果还是很多,继续跑分析脚本,一轮一轮迭代。

避坑提醒:别让优化动作反过来拖垮业务

慢查询优化脚本只是帮你发现问题,真正动手改库时要谨慎。
以下几点最容易踩坑:

  • 不要在生产环境直接 ALTER TABLE 大表。加索引会锁表,建议选择业务低峰期,或用 pt-online-schema-change 这类工具在线变更。
  • 注意磁盘空间。慢查询日志如果长时间不清理,可能占用几十 GB。脚本跑完后及时压缩或定期清理。
分享到:
上一篇
多语言外贸站点Nginx完整多域名隔离配置教程
下一篇
sub2api常见报错:cookie失效、会话过期
1
系统公告

机房迁移升级通知

尊敬的用户: IP 段 103.23.148.x、156.224.29.x 原香港一区线路波动、攻击频繁,平台定于 7 月 5 日凌晨分批迁移至香港 GIA 机房,硬件升级 AMD 铂金机型。 迁移均在凌晨操作,最大程度降低业务影响,迁移期间服务器临时关机; 升级后配置不降低、费用不涨价,数据默认同步迁移; 迁移后 IP 全部更换,请及时修改域名解析、防火墙白名单; 建议提前备份重要数据,有问题可联系在线客服。 感谢理解与支持! 泽御云科技 2026.06.30
服务中心
客服
在线客服
24小时为您服务
咨询
联系我们
联系我们,为您的业务提供专属服务。
24/7 技术支持
如果您遇到寻求进一步的帮助,请过工单与我们进行联系。
24/7 即时支持
泽御云
售前客服
泽御云
泽御云
售后客服
泽御云
技术支持
评价
您对当前页面的整体感受是否满意?
😞
非常不满意
😕
不满意
😐
一般
🙂
满意
😊
非常满意