framework
framework/mysql/diagnosis/slow-query-triage.md
medium
mysql-slow-query-triage
MySQL 慢查询定位流程 — 开慢查询日志抓慢 SQL,用 pt-query-digest 聚合排序找 TopN,再逐条 EXPLAIN 定位。Use when 系统变慢要找慢 SQL / 配慢查询日志 / 不知从哪入手优化时。
慢查询日志slow query loglong_query_timept-query-digestmysqldumpslow慢 sql 定位
paths
*.sql*.yml*.cnf*.properties
MySQL · 慢查询定位流程
本条只管「怎么找出是哪条 SQL 慢」的流程。找到后单条 EXPLAIN 怎么读见
explain-reading.md;定位是索引问题后怎么改见../index/index.md。
定位流程(按顺序)
- 开慢查询日志,设阈值:
# my.cnf
slow_query_log = 1
slow_query_log_file = /var/log/mysql/slow.log
long_query_time = 1 # 超过 1s 记录(按业务调,可先 0.5)
log_queries_not_using_indexes = 1 # 未走索引的也记
- 聚合排序找 TopN(不要手翻日志):
# 自带工具,按平均耗时排序前 10
mysqldumpslow -s at -t 10 /var/log/mysql/slow.log
# 或 Percona 工具,按总耗时聚合(推荐,能合并参数不同的同型 SQL)
pt-query-digest /var/log/mysql/slow.log
- 逐条 EXPLAIN Top 慢 SQL → 见 explain-reading。
- 对症下药:没走索引→建/改索引;扫太多行→加过滤条件;filesort/临时表→调索引覆盖排序分组;SQL 写法问题→改写(见 index-fail-cases)。
- 复测:改完再 EXPLAIN + 实跑确认
rows/耗时下降。
优先级判断
- 按「总耗时 = 单次耗时 × 调用次数」排序,不是只看单次最慢。一条 50ms 但每秒调 1000 次的,比一条 2s 但每天跑 1 次的更值得优化。
pt-query-digest的 grand total / Response time 占比直接给出这个排序。
临时排查(不便开日志时)
-- 看当前正在执行的长查询
SELECT * FROM information_schema.PROCESSLIST WHERE TIME > 5 AND COMMAND='Query';
-- 性能 schema 里的语句汇总(按平均耗时)
SELECT * FROM performance_schema.events_statements_summary_by_digest
ORDER BY AVG_TIMER_WAIT DESC LIMIT 10;
自检
- [ ] 慢查询日志已开、
long_query_time设了合理阈值? - [ ] 用
pt-query-digest/mysqldumpslow聚合排序,而非肉眼翻日志? - [ ] 按「总耗时(含调用频次)」而非单次耗时定优先级?
- [ ] 每条优化后都复测确认
rows/耗时确实下降?