sql慢查询日志是定位性能瓶颈最直接的入口,需开启配置、用工具筛选关键字段、结合explain分析执行计划,并针对性优化索引、避免隐式转换、减少select*和深分页。

SQL 慢查询日志是定位性能瓶颈最直接的入口。关键不是“有没有开”,而是“怎么读、怎么筛、怎么改”。重点看执行时间长、扫描行数多、未命中索引的语句,再结合执行计划(EXPLAIN)验证实际执行路径。
开启并配置慢查询日志
mysql 默认关闭慢查询日志,需手动启用并合理设置阈值:
- 在 my.cnf 中添加:slow_query_log = ON、slow_query_log_file = /var/log/mysql/slow.log、long_query_time = 1.0(单位秒,建议从 1 开始,业务稳定后可调至 0.5)
- 动态开启(无需重启):SET GLOBAL slow_query_log = ON;,但该设置在服务重启后失效
- 补充记录未使用索引的查询:log_queries_not_using_indexes = ON(注意:这会产生大量日志,上线前建议先评估)
高效筛选和解读慢日志
原始日志可读性差,优先用工具或命令聚焦问题语句:
- 用 mysqldumpslow 快速统计(例如:mysqldumpslow -s t -t 10 /var/log/mysql/slow.log 查看耗时 Top 10 的语句)
- 用 pt-query-digest(Percona Toolkit)深度分析:支持聚合、报告、异常检测,还能生成优化建议
- 关注日志中三类关键字段:Query_time(真实执行耗时)、Lock_time(锁等待时间高说明存在锁争用)、Rows_examined(扫描行数远大于 Rows_sent 表示过滤效率低,大概率缺索引或索引失效)
定位瓶颈:从 EXPLAIN 看执行计划
对慢日志中的 SQL 执行 EXPLAIN,重点关注以下几列:
- type:越靠右越好(system ≈ const > eq_ref > ref > range > index > ALL)。出现 ALL 表示全表扫描,必须优化
- key 和 key_len:是否命中预期索引?key_len 是否符合联合索引最左匹配?比如索引为 (a,b,c),WHERE a=1 AND b>2 会用到前两列,key_len 应反映 a 和 b 的字节长度
- rows:预估扫描行数,若远高于实际返回结果,说明索引选择性差或统计信息过期(可执行 ANALYZE table table_name; 更新)
- Extra:出现 Using filesort 或 Using temporary 是性能红灯,通常因排序/分组字段未走索引,或 GROUP BY 与 ORDER BY 字段不一致
常见优化手段与避坑点
优化不是加索引就完事,要结合场景判断:
- 为 WHERE + ORDER BY 组合建联合索引,遵循“过滤字段在前、排序字段在后”原则(如 WHERE status=1 ORDER BY created_at DESC,适合建 (status, created_at))
- 避免隐式类型转换:比如字段是 VARCHAR,却用数字查询(WHERE mobile = 13800138000),会导致索引失效;统一加引号(WHERE mobile = ‘13800138000’)
- 少用 SELECT *,尤其大宽表;只查必要字段,减少网络传输和临时表开销
- 分页深翻慎用 OFFSET:LIMIT 10000,20 效率极低,改用游标分页(如记录上一页最大 ID,用 WHERE id > xxx LIMIT 20)
- 定期清理历史慢日志,避免磁盘写满;可配合 logrotate 配置自动轮转