适用 MySQL 5.7 / 8.0,分为:慢查询日志开启检查、在线抓慢 SQL、分析慢日志、锁 & 事务、索引检查、性能视图排查 ⚠️ 注意:线上执行尽量避开高峰;
performance_schema需要提前开启;部分 SQL 需要SUPER权限
一、先检查慢查询配置(必跑)
-- 查看慢查询整体配置
SHOW VARIABLES LIKE 'slow_query_log%';
SHOW VARIABLES LIKE 'long_query_time'; -- 慢查询阈值,单位秒
SHOW VARIABLES LIKE 'log_queries_not_using_indexes'; -- 是否记录未走索引SQL
SHOW VARIABLES LIKE 'log_output'; -- FILE / TABLE,TABLE则存在mysql.slow_log表
-- 在线开启慢查询(临时,重启失效;生产建议my.cnf持久化)
-- SET GLOBAL slow_query_log = ON;
-- SET GLOBAL long_query_time = 1;
-- SET GLOBAL log_queries_not_using_indexes = ON;
如果 log_output=TABLE,可以直接查表:
-- 查询mysql.slow_log(log_output=table时可用)
SELECT
start_time,
query_time,
lock_time,
rows_sent,
rows_examined,
sql_text
FROM mysql.slow_log
ORDER BY start_time DESC
LIMIT 50;
二、performance_schema 实时抓慢 SQL(不用等慢日志落盘,推荐)
前提:
performance_schema=ON,8.0 默认开启;5.7 需要在 my.cnf 配置
-- 查看是否开启statement采集
SELECT * FROM performance_schema.setup_consumers WHERE NAME LIKE 'events_statements%';
-- 抓取最近耗时高SQL
SELECT
EVENT_ID,
SCHEMA_NAME,
SQL_TEXT,
TIMER_WAIT / 1000000000 AS exec_time_ms,
LOCK_TIME / 1000000000 AS lock_time_ms,
ROWS_SENT,
ROWS_EXAMINED,
ROWS_AFFECTED,
CREATED
FROM performance_schema.events_statements_current
WHERE TIMER_WAIT / 1000000000 > 100 -- 大于100ms,按需改
ORDER BY TIMER_WAIT DESC
LIMIT 50;
统计TOP 耗时 SQL(汇总聚合,看热点)
SELECT
DIGEST,
DIGEST_TEXT,
COUNT_STAR AS exec_count,
SUM_TIMER_WAIT / 1000000000 AS sum_time_ms,
AVG_TIMER_WAIT / 1000000000 AS avg_time_ms,
MAX_TIMER_WAIT / 1000000000 AS max_time_ms,
SUM_ROWS_EXAMINED,
SUM_ROWS_SENT
FROM performance_schema.events_statements_summary_by_digest
WHERE SUM_TIMER_WAIT > 0
ORDER BY SUM_TIMER_WAIT DESC
LIMIT 30;
DIGEST:SQL 指纹,相同结构不同参数 SQL 会归为一条,非常适合抓热点
三、锁、长事务排查(很多 “慢 SQL” 不是 SQL 本身慢,是被锁等)
1. 查看当前事务 & 长事务
SELECT
trx_id,
trx_state,
trx_started,
NOW() - trx_started AS trx_duration_sec,
trx_query,
trx_mysql_thread_id,
trx_isolation_level
FROM information_schema.innodb_trx
ORDER BY trx_started ASC;
2. 查看锁等待(阻塞关系)
SELECT
r.trx_id AS waiting_trx_id,
r.trx_mysql_thread_id AS waiting_thread,
r.trx_query AS waiting_sql,
b.trx_id AS blocking_trx_id,
b.trx_mysql_thread_id AS blocking_thread,
b.trx_query AS blocking_sql
FROM information_schema.innodb_lock_waits w
JOIN information_schema.innodb_trx r ON w.requesting_trx_id = r.trx_id
JOIN information_schema.innodb_trx b ON w.blocking_trx_id = b.trx_id;
3. 查看活跃连接、跑中的 SQL
SHOW PROCESSLIST;
-- 完整版(推荐)
SELECT
ID,
USER,
HOST,
DB,
COMMAND,
TIME,
STATE,
INFO
FROM information_schema.PROCESSLIST
WHERE COMMAND != 'Sleep'
ORDER BY TIME DESC;
杀掉阻塞会话:KILL 线程ID;
四、索引检查脚本(找到慢 SQL 后,检查表索引、缺失索引、冗余索引)
-- 查看表索引
SHOW INDEX FROM `库名`.`表名`;
-- 检查没用过的索引(sys库,MySQL8.0自带sys,5.7需要导入sys schema)
SELECT
OBJECT_SCHEMA,
OBJECT_NAME,
INDEX_NAME
FROM sys.schema_unused_indexes;
-- 冗余索引
SELECT * FROM sys.schema_redundant_indexes;
-- 查看索引使用统计
SELECT * FROM performance_schema.table_io_waits_summary_by_index_usage
WHERE INDEX_NAME IS NOT NULL AND SUM_TIMER_WAIT > 0
ORDER BY SUM_TIMER_WAIT DESC;
五、explain 分析模板(拿到慢 SQL 后套这个)
EXPLAIN ANALYZE -- MySQL8.0.18+支持,直接看真实执行耗时;5.7去掉ANALYZE
SELECT xxx FROM xxx WHERE xxx;
快速解读字段
type:ALL 全表扫描危险
Extra:Using filesort / Using temporary 重点优化
rows:预估扫描行数
key:实际使用索引
六、命令行工具:mysqldumpslow(分析慢查询日志文件,shell 脚本)
# 慢日志路径通过 show variables like 'slow_query_log_file' 获取
# 取耗时最多的前10条
mysqldumpslow -s t -t 10 /var/lib/mysql/localhost-slow.log
# 取扫描行数最多
mysqldumpslow -s r -t 10 /var/lib/mysql/localhost-slow.log
# 筛选带select的慢SQL
mysqldumpslow -s t -t 20 -g "select" /var/lib/mysql/localhost-slow.log
参数说明:
-s t:按总耗时;-s at 平均耗时;-s r 返回行数;-s c 执行次数
-t N 取 TOP N
-g 正则过滤
七、Shell 一键采集脚本(可定时 crontab 输出慢 SQL 快照)
#!/bin/bash
MYSQL_USER="root"
MYSQL_PASS="xxxx"
MYSQL_SOCKET="/tmp/mysql.sock"
LOG_FILE="/tmp/mysql_slow_snapshot.log"
echo "===== $(date '+%Y-%m-%d %H:%M:%S') 慢SQL快照 =====" >> $LOG_FILE
mysql -u$MYSQL_USER -p$MYSQL_PASS -S $MYSQL_SOCKET -e "
SELECT
DIGEST_TEXT,
COUNT_STAR,
SUM_TIMER_WAIT/1000000000 sum_ms,
AVG_TIMER_WAIT/1000000000 avg_ms,
MAX_TIMER_WAIT/1000000000 max_ms,
SUM_ROWS_EXAMINED,
SUM_ROWS_SENT
FROM performance_schema.events_statements_summary_by_digest
ORDER BY sum_ms DESC LIMIT 20;
" >> $LOG_FILE
echo -e "\n" >> $LOG_FILE
八、排查标准流程(配套脚本使用)
看 processlist:是否有长 SQL / 锁等待
看 innodb_trx + innodb_lock_waits:区分是慢还是阻塞
performance_schema digest 抓 TOP 热点 SQL 指纹
explain 分析单条 SQL 执行计划
检查表索引:缺失、冗余、从未使用索引
mysqldumpslow 离线分析历史慢日志
业务侧评估:N+1、深分页、大 in、无索引
九、踩坑提醒
performance_schema会增加少量性能开销,线上不要一直开全量采集,用完可以关闭log_queries_not_using_indexes打开后,小表全扫描也会大量刷慢日志,容易淹没真实慢 SQL长事务、gap 锁、自锁,表象也是 SQL 卡住,不一定是索引问题
MySQL 5.7 没有
EXPLAIN ANALYZE