一句话定位:慢查询日志是 MySQL 的 "性能监控雷达" ,自动记录执行超过 long_query_time 的 SQL,是定位性能瓶颈的黄金标准。

一、核心工作流程

graph TB A[客户端发送 SQL] --> B{执行时间 > long_query_time?} B -->|是| C{是否使用索引?} C -->|是| D[记录慢查询日志] C -->|否,且 log_queries_not_using_indexes=ON| D C -->|否,且 OFF| E[不记录] B -->|否| E D --> F[日志写入文件] F --> G[分析工具: pt-query-digest] G --> H[生成报告: 慢查询 Top 10]

二、极速配置模板(生产直接抄)

[mysqld]
# 1. 开启慢查询日志(默认 OFF)
slow_query_log = ON
slow_query_log_file = /data/mysql/log/slow.log  # 建议独立磁盘

# 2. 时间阈值(秒),0.1 = 100ms
long_query_time = 0.1

# 3. 记录未使用索引的查询(默认 OFF)
log_queries_not_using_indexes = ON

# 4. 日志格式(TABLE 支持 SQL 查询,FILE 传统)
log_output = FILE,TABLE  # 同时写文件和 mysql.slow_log 表

# 5. 采样率(避免日志过大)
log_throttle_queries_not_using_indexes = 100  # 每分钟最多记录 100 条无索引查询

# 6. 管理语句(ALTER, ANALYZE 等)
log_slow_admin_statements = ON

# 7. 记录到表的最大行数
slow_log_table_size = 10000  # mysql.slow_log 表最多 1 万行

三、关键参数详解

1. slow_query_log(开关)

slow_query_log = ON
  • 动态开启 :SET GLOBAL slow_query_log = ON;

  • 无需重启 ,但建议配置文件中静态设置

2. long_query_time(阈值)

long_query_time = 0.1  # 100ms
  • 单位:秒 ,支持小数

  • 推荐值 :

    • 互联网业务:0.1 ~ 0.5(100ms~500ms)

    • 后台/报表:1 ~ 2

  • 动态调整 :SET GLOBAL long_query_time = 0.1;

  • 会话级测试 :SET SESSION long_query_time = 0; 记录所有查询

3. log_queries_not_using_indexes(无索引查询)

log_queries_not_using_indexes = ON
  • 作用:即使执行时间很短,只要没走索引就记录

  • 注意:可能导致日志暴增,配合 log_throttle_queries_not_using_indexes 使用

4. log_throttle_queries_not_using_indexes(限速)

log_throttle_queries_not_using_indexes = 100
  • 作用 :每分钟最多记录 100 条无索引查询,防日志打爆

  • 推荐 :100 ~ 1000

5. log_slow_admin_statements(管理语句)

log_slow_admin_statements = ON
  • 作用 :记录 ALTER TABLE, ANALYZE, CREATE INDEX

  • 推荐 :ON,慢 DDL 影响业务


四、日志分析工具(实战命令)

1. mysqldumpslow(MySQL 自带)

# 按执行时间排序,Top 10
mysqldumpslow -s t -t 10 /data/mysql/log/slow.log

# 按平均锁定时间排序
mysqldumpslow -s al -t 10 /data/mysql/log/slow.log

# 过滤特定表
mysqldumpslow -t 10 -g 'users' /data/mysql/log/slow.log

2. pt-query-digest(Percona Toolkit,强烈推荐)

# 安装
yum install percona-toolkit

# 分析慢查询日志,生成报告
pt-query-digest /data/mysql/log/slow.log > slow_report.html

# 按时间范围分析
pt-query-digest --since='2024-01-01 00:00:00' \
                --until='2024-01-01 23:59:59' \
                /data/mysql/log/slow.log > report.html

# 功能:
# - 按总耗时、平均耗时、锁定时间排序
# - 显示执行计划(EXPLAIN)
# - 推荐索引
# - 可视化图表

五、生产环境实践

1. 日志切割与归档

# 每天凌晨切割慢查询日志
# /etc/cron.daily/mysql_slow_log_rotate
#!/bin/bash
LOG_DIR="/data/mysql/log"
DATE=$(date +%Y%m%d)
mv ${LOG_DIR}/slow.log ${LOG_DIR}/slow.log.${DATE}
mysqladmin flush-logs slow  # 通知 MySQL 重新打开日志

# 压缩旧日志
gzip ${LOG_DIR}/slow.log.${DATE}

# 保留 30 天
find ${LOG_DIR} -name "slow.log.*" -mtime +30 -delete

2. 存储位置建议

[mysqld]
# 慢查询日志推荐独立磁盘,避免与数据盘竞争 IO
slow_query_log_file = /ssd/log/slow.log
# 或独立分区挂载
# /dev/nvme1n1p1 /ssd/log ext4 defaults,noatime 0 0

3. 性能影响

  • 开销 :< 5%(CPU 和 I/O)

  • 风险 :日志文件过大(> 100GB)会影响日志轮转

  • 缓解 :配合 log_throttle_queries_not_using_indexes

4. 慢查询日志表

-- 查看 mysql.slow_log 表(需 log_output=TABLE)
SELECT * FROM mysql.slow_log 
ORDER BY query_time DESC 
LIMIT 10;

-- 优点:可用 SQL 直接查询
-- 缺点:表过大影响性能,需定期清理
TRUNCATE TABLE mysql.slow_log;

六、慢查询优化流程(实战)

1. 发现慢查询
   pt-query-digest --since=24h /data/mysql/log/slow.log > report.html

2. 定位 TOP 1 查询
   # report.html 显示:
   # Query 1: 平均耗时 2.3s, 执行 1000 次, 扫描 100 万行

3. EXPLAIN 分析
   mysql> EXPLAIN SELECT * FROM users WHERE phone='13800138000';
   # 结果:type=ALL (全表扫描)

4. 优化方案
   - 添加索引: ALTER TABLE users ADD INDEX idx_phone(phone);
   - 或改写 SQL: SELECT id, name FROM users WHERE phone=?;

5. 验证
   mysql> EXPLAIN SELECT ...;
   # 结果:type=ref (走索引)
   # 再次执行: 耗时 2.3s → 10ms

6. 监控
   pt-query-digest /data/mysql/log/slow.log --since='1h' | grep 'phone'
   # 确认优化后不再出现

七、慢查询日志告警

# 检测 1 分钟内新增慢查询数量
#!/bin/bash
LOG_FILE="/data/mysql/log/slow.log"
COUNT=$(tail -n 10000 $LOG_FILE | grep -c "$(date '+%Y-%m-%d %H:%M')")

if [ $COUNT -gt 100 ]; then
  echo "告警: 1 分钟内新增 $COUNT 条慢查询" | mail -s "MySQL 慢查询告警" dba@company.com
fi

八、一句话总结

慢查询日志是性能优化的唯一真相来源long_query_time = 0.1,配合 pt-query-digest 每周生成报告,所有慢 SQL 都必须有索引,没有例外。