前言:做MySQL开发或运维的同学,肯定遇到过这样的场景------系统突然卡顿、接口响应超时,排查一圈发现是数据库拖了后腿,但又不知道具体是哪条SQL出了问题。其实,MySQL自带的慢查询日志,就是解决这类问题的"神器"。
但很多人要么不会配置慢查询日志,要么配置后日志杂乱无章、无从分析,甚至因为参数配置不当,导致日志占用大量磁盘空间,反而拖慢数据库性能。
本文将从「慢查询日志核心参数配置」「日志分析工具使用」「慢查询排查实战」「常见踩坑点」四个维度,手把手教你搞定MySQL慢查询与日志体系优化,全程实战、可直接套用,无论是新手还是资深运维,都能快速上手。
适合人群:MySQL后端开发、运维工程师、DBA,无需深入底层,聚焦"实用、可落地",帮你快速定位并解决SQL性能瓶颈。
一、先搞懂:慢查询日志的核心作用
慢查询日志(Slow Query Log)是MySQL内置的日志功能,专门用于记录执行时间超过预设阈值的SQL语句,以及未使用索引、执行效率低下的查询操作,其核心作用有3点:
-
精准定位性能瓶颈:快速找到系统中执行缓慢的SQL,明确优化方向,避免"盲目调参";
-
辅助SQL优化:通过日志详情,分析SQL执行耗时、扫描行数、锁等待等信息,为SQL改写、索引优化提供依据;
-
提前预警风险:通过监控慢查询数量和趋势,预判数据库性能退化,提前介入优化,避免线上故障。
注意:慢查询日志默认是关闭的,且默认阈值设置过宽(MySQL 5.7/8.0默认10秒),无法满足生产环境需求,必须手动优化配置。
二、核心参数详解&实战配置(按优先级排序)
所有参数均配置在MySQL配置文件(my.cnf/my.ini)的[mysqld]段,部分参数支持动态调整(无需重启MySQL),下文会明确标注。配置核心原则:精准记录、不冗余、不占用过多资源。
第一类:慢查询日志核心参数(必配)
1. slow_query_log:开启/关闭慢查询日志
-
作用:控制慢查询日志的启用状态,是所有慢查询配置的基础。
-
默认值:OFF(关闭,生产环境必须开启)。
-
可选值:ON(开启)、OFF(关闭)。
-
配置方式:
-
永久配置(推荐,重启生效):
[mysqld] ``slow_query_log = ON -
动态配置(无需重启,临时生效,重启后失效):
SET GLOBAL slow_query_log = ON;
-
-
踩坑点:开启后会产生日志文件,需配合日志滚动和过期清理,避免磁盘爆满。
2. slow_query_log_file:指定慢查询日志存储路径
-
作用:设置慢查询日志文件的存储位置和文件名,便于后续分析和管理。
-
默认值:MySQL默认存储在数据目录下,文件名通常为host_name-slow.log(如localhost-slow.log),不便于区分和管理。
-
推荐配置 :单独指定路径(建议放在非数据盘,避免占用数据盘空间),示例:
[mysqld] ``# 自定义慢查询日志路径,根据实际服务器路径调整 ``slow_query_log_file = /data/mysql/log/mysql-slow.log -
注意事项:确保MySQL进程对该路径有写入权限,否则日志无法生成(可通过chmod授权解决)。
3. long_query_time:慢查询阈值(核心中的核心)
-
作用:设置"慢查询"的判定标准,即执行时间超过该值的SQL,会被记录到慢查询日志中。
-
默认值:10秒(过宽,生产环境需调整,否则无法捕捉到大部分慢查询)。
-
推荐配置:
-
普通业务(如后台管理系统):1-2秒
-
高并发业务(如电商、接口服务):0.5-1秒
-
核心业务(如支付、秒杀):0.1-0.5秒
-
-
配置示例 :
[mysqld] ``# 设置慢查询阈值为1秒(支持小数,如0.5表示500毫秒) ``long_query_time = 1 -
踩坑点:
-
动态修改该参数后,需重新连接MySQL会话,新阈值才会生效(当前会话仍使用旧阈值);
-
阈值不要设置过小(如0.01秒),否则会记录大量无关SQL,导致日志冗余、分析困难,且占用磁盘和CPU资源。
-
第二类:日志过滤与补充参数(优化日志质量)
1. log_queries_not_using_indexes:记录未使用索引的查询
-
作用:即使SQL执行时间未超过long_query_time,只要未使用索引(全表扫描),也会被记录到慢查询日志中------这类SQL是性能隐患,后续可能演变成慢查询。
-
默认值:OFF(不记录,生产环境建议开启)。
-
推荐配置 :ON(开启),但需配合限流参数,避免日志暴涨。
[mysqld] ``log_queries_not_using_indexes = ON ``# 可选:限制未使用索引查询的日志记录频率(每分钟最多记录10条),避免日志冗余 ``log_throttle_queries_not_using_indexes = 10 -
说明:log_throttle_queries_not_using_indexes默认值为0(无限制),开启后若未配置限流,当存在大量全表扫描SQL时,会导致日志快速增大,占用大量磁盘空间。
2. log_slow_admin_statements:记录慢管理语句
-
作用:记录执行缓慢的管理语句,包括ALTER TABLE、ANALYZE TABLE、CHECK TABLE、CREATE INDEX、DROP INDEX、OPTIMIZE TABLE、REPAIR TABLE等------这类语句执行时会锁表,耗时过长会影响业务可用性。
-
默认值:OFF(不记录,生产环境建议开启)。
-
配置示例 :
[mysqld] ``log_slow_admin_statements = ON -
注意:这类语句通常由运维执行,记录后便于排查运维操作导致的数据库卡顿问题。
3. min_examined_row_limit:最小扫描行数阈值
-
作用:设置SQL扫描行数的最小值,只有扫描行数超过该值,且满足慢查询条件(超时或未用索引),才会被记录到日志中------避免记录扫描行数少、即使超时也不影响性能的SQL(如查询10行数据耗时1.1秒)。
-
默认值:0(所有满足条件的SQL都记录)。
-
推荐配置 :100(扫描行数超过100行的慢查询才记录),可根据业务调整:
[mysqld] ``min_examined_row_limit = 100
4. log_output:日志输出方式
-
作用:控制慢查询日志的输出格式,支持文件、数据库表两种方式,可单独输出或同时输出。
-
可选值:
-
FILE:输出到文件(推荐,便于工具分析,占用资源少);
-
TABLE:输出到MySQL内置的mysql.slow_log表中(便于用SQL查询,但会占用数据库资源);
-
NONE:不输出任何日志(不推荐)。
-
-
推荐配置 :FILE(生产环境优先),示例:
[mysqld] ``log_output = FILE
第三类:日志滚动与清理参数(避免磁盘爆满)
慢查询日志会持续增长,若不做清理,会逐渐占满磁盘,导致MySQL无法正常运行,因此必须配置日志滚动和过期清理。
1. expire_logs_days:日志自动过期时间
-
作用:设置慢查询日志(及其他MySQL日志)的自动过期时间,超过该时间的日志会被自动清理。
-
默认值:0(永不过期,必须修改)。
-
推荐配置 :3-7天(根据业务需求调整,核心业务可保留7天,普通业务保留3天):
[mysqld] ``# 慢查询日志保留3天,自动清理过期日志 ``expire_logs_days = 3
2. log_rotate:日志滚动开关
-
作用:开启日志滚动,当日志文件达到指定大小后,自动生成新的日志文件(如mysql-slow.001.log、mysql-slow.002.log),避免单个日志文件过大,便于管理和分析。
-
默认值:OFF(关闭,MySQL 8.0+支持,5.7需手动配置日志切割脚本)。
-
配置示例 (MySQL 8.0+):
[mysqld] ``log_rotate = ON ``# 单个日志文件最大大小(如100M),达到该大小后自动滚动 ``max_log_size = 104857600 -
补充:MySQL 5.7用户可通过Linux定时任务(crontab)+ logrotate工具,实现日志滚动(下文实战部分会详细说明)。
场景化完整配置方案(可直接复制使用)
以下配置覆盖「普通业务」「高并发业务」两种场景,修改路径后可直接粘贴到my.cnf,重启MySQL生效。
场景1:普通业务(后台管理系统、小型应用,4G内存服务器)
sql
[mysqld]
# 慢查询核心配置
slow_query_log = ON
slow_query_log_file = /data/mysql/log/mysql-slow.log
long_query_time = 1
log_output = FILE
# 日志过滤与补充
log_queries_not_using_indexes = ON
log_throttle_queries_not_using_indexes = 10
log_slow_admin_statements = ON
min_examined_row_limit = 100
# 日志清理与滚动
expire_logs_days = 3
# MySQL 8.0+ 日志滚动配置
log_rotate = ON
max_log_size = 104857600
场景2:高并发业务(电商、接口服务,16G内存服务器)
sql
[mysqld]
# 慢查询核心配置
slow_query_log = ON
slow_query_log_file = /data/mysql/log/mysql-slow.log
long_query_time = 0.5 # 阈值设为500毫秒,捕捉更多潜在慢查询
log_output = FILE
# 日志过滤与补充
log_queries_not_using_indexes = ON
log_throttle_queries_not_using_indexes = 20 # 适当提高限流,避免遗漏
log_slow_admin_statements = ON
min_examined_row_limit = 50 # 扫描行数超过50行就记录,提前发现隐患
# 日志清理与滚动
expire_logs_days = 7 # 核心业务保留7天日志,便于追溯
log_rotate = ON
max_log_size = 209715200 # 单个日志文件最大200M
三、慢查询日志分析工具实战(重点!)
配置好慢查询日志后,会生成大量日志文件,直接打开查看会杂乱无章,无法快速定位核心问题。以下推荐2个最常用、最实用的分析工具,全程实战可落地。
工具1:MySQL自带工具 mysqldumpslow(简单易用,无需额外安装)
mysqldumpslow是MySQL自带的慢查询分析工具,可对日志进行聚合、排序,快速筛选出最耗时、执行最频繁的SQL,适合快速排查问题。
核心命令(直接复制执行)
sql
# 1. 按执行时间排序,显示前10条最慢的SQL(最常用)
mysqldumpslow -s t -t 10 /data/mysql/log/mysql-slow.log
# 2. 按执行次数排序,显示前10条执行最频繁的慢SQL
mysqldumpslow -s c -t 10 /data/mysql/log/mysql-slow.log
# 3. 按锁等待时间排序,显示前10条锁等待最长的SQL
mysqldumpslow -s l -t 10 /data/mysql/log/mysql-slow.log
# 4. 筛选包含指定表(如order表)的慢SQL
mysqldumpslow -g "order" /data/mysql/log/mysql-slow.log
# 5. 筛选指定用户(如root)执行的慢SQL,保留原始SQL格式
mysqldumpslow -a -g "root" /data/mysql/log/mysql-slow.log
命令参数解读
-
-s:排序方式(t=按时间、c=按次数、l=按锁等待时间);
-
-t:显示前N条结果;
-
-g:匹配关键词(支持正则表达式);
-
-a:显示完整的SQL语句(默认会省略部分内容)。
结果解读示例
bash
Reading mysql slow query log from /data/mysql/log/mysql-slow.log
Count: 100 Time=1.20s (120s) Lock=0.01s (1s) Rows=100.0 (10000), root[root]@localhost
SELECT * FROM order WHERE user_id = N ORDER BY create_time DESC LIMIT N
-
Count:该SQL执行次数(100次);
-
Time:单次执行平均时间(1.20秒),括号内是总耗时(120秒);
-
Lock:单次锁等待平均时间(0.01秒),括号内是总锁等待时间(1秒);
-
Rows:单次返回平均行数(100行),括号内是总行数(10000行);
-
后续是SQL模板(N表示参数占位符),可根据该模板定位具体SQL。
工具2:Percona Toolkit(pt-query-digest,专业级分析工具)
mysqldumpslow适合快速排查,而pt-query-digest是专业级慢查询分析工具,功能更强大,可生成结构化报告,精准定位高频慢查询、大事务慢查询,是生产环境首选工具。
1. 安装步骤(Linux系统,直接复制执行)
bash
# 1. 安装依赖(CentOS示例,Ubuntu需替换为apt-get)
yum install epel-release -y
yum install perl-DBI perl-DBD-MySQL perl-Time-HiRes -y
# 2. 下载并安装Percona Toolkit
wget https://downloads.percona.com/downloads/percona-toolkit/3.5.4/binary/redhat/7/x86_64/percona-toolkit-3.5.4-2.el7.x86_64.rpm
yum install percona-toolkit-3.5.4-2.el7.x86_64.rpm -y
# 3. 验证安装(输出版本号即成功)
pt-query-digest --version
2. 核心命令(实战常用)
bash
# 1. 基础用法:分析慢查询日志,生成结构化报告(输出到文件,便于查看)
pt-query-digest /data/mysql/log/mysql-slow.log > slow_query_report.log
# 2. 进阶用法:只分析近24小时的慢查询,按SQL指纹聚合(避免重复SQL)
pt-query-digest --since=24h --group-by fingerprint /data/mysql/log/mysql-slow.log > last24h_slow.log
# 3. 精准分析:只分析指定时间范围的慢查询(如2026-04-08 08:00-18:00)
pt-query-digest /data/mysql/log/mysql-slow.log \
--since '2026-04-08 08:00:00' \
--until '2026-04-08 18:00:00' \
> worktime_slow.log
# 4. 筛选分析:只分析执行时间超过1秒、扫描行数超过1000的慢查询
pt-query-digest --filter "Query_time > 1 AND Rows_examined > 1000" /data/mysql/log/mysql-slow.log
3. 报告核心解读(重点关注4个模块)
打开生成的报告文件(如slow_query_report.log),重点关注以下内容,快速定位问题:
-
总体统计(Overall):显示总慢查询数、唯一SQL指纹数、QPS等,快速判断慢查询规模(如"Total queries: 1200, Unique: 23"表示1200条慢查询,对应23种不同的SQL);
-
慢查询排行(Rank):按总耗时占比排序,优先优化"Time% > 10%"且"单次耗时 > 500ms"的SQL,这类SQL是性能瓶颈的核心;
-
SQL详情(Query):显示SQL完整语句、执行次数、平均耗时、扫描行数、锁等待时间等,重点关注"Rows_examined"(扫描行数),若扫描行数远大于返回行数,说明存在全表扫描或索引失效;
-
执行时间分布(Query_time distribution):显示不同耗时区间的SQL数量,若"10s+"占比高,说明存在严重性能问题,需紧急处理。
四、慢查询排查&优化实战案例(真实场景)
结合真实生产场景,教你从"发现慢查询"到"优化解决"的完整流程,可直接套用。
案例:电商订单列表接口卡顿,响应超时(3秒+)
步骤1:通过慢查询日志定位问题SQL
-
执行pt-query-digest分析慢查询日志:
pt-query-digest /data/mysql/log/mysql-slow.log > slow_report.log -
打开报告,发现高频慢查询:
SELECT * FROM orders WHERE user_id = 1001 AND status IN ('paid', 'shipped') ORDER BY create_time DESC LIMIT 0, 10; -
日志详情:执行次数500次,平均耗时2.8秒,扫描行数100000+,锁等待时间0.05秒------核心问题:扫描行数过多(全表扫描)。
步骤2:分析SQL执行计划(定位根因)
使用EXPLAIN命令分析该SQL的执行计划,判断是否使用索引: EXPLAIN SELECT * FROM orders WHERE user_id = 1001 AND status IN ('paid', 'shipped') ORDER BY create_time DESC LIMIT 0, 10;
执行结果分析:type=ALL(全表扫描),key=NULL(未使用索引),Extra=Using filesort(需额外排序,耗时严重)------根因:未为查询条件和排序字段创建合适的索引。
步骤3:优化方案落地
-
创建联合索引(覆盖查询条件和排序字段,避免全表扫描和文件排序):
ALTER TABLE orders ADD INDEX idx_user_status_time(user_id, status, create_time DESC); -
SQL改写(避免SELECT *,只查询需要的字段,实现覆盖索引,减少回表耗时):
SELECT id, user_id, status, amount, create_time FROM orders ``WHERE user_id = 1001 AND status IN ('paid', 'shipped') ``ORDER BY create_time DESC LIMIT 10;
步骤4:优化验证
-
再次执行EXPLAIN,type=range(索引范围扫描),key=idx_user_status_time(使用索引),Extra=Using index(覆盖索引,无需回表);
-
查看慢查询日志,该SQL执行时间降至25ms,执行次数不变,接口响应时间恢复正常(300ms内);
-
持续监控1天,该SQL未再出现在慢查询日志中,优化生效。
五、常见踩坑点总结(必看!)
-
开启慢查询后,日志暴涨导致磁盘爆满:未配置expire_logs_days和日志滚动,需及时设置日志过期时间,MySQL 5.7用户需配置定时切割脚本;
-
long_query_time设置过小/过大:过小会记录大量无关SQL,过大无法捕捉潜在慢查询,建议根据业务场景设置0.5-2秒;
-
开启log_queries_not_using_indexes后,未配置限流:导致大量全表扫描SQL(即使耗时短)被记录,需配合log_throttle_queries_not_using_indexes限流;
-
动态修改参数后,未重新连接会话:long_query_time等参数动态修改后,当前会话仍使用旧值,需重新连接MySQL才能生效;
-
只依赖工具分析,不看执行计划:工具只能定位慢SQL,无法判断根因,需结合EXPLAIN分析执行计划,才能精准优化;
-
日志路径权限不足,导致日志无法生成:需确保MySQL进程对日志路径有写入权限,可通过chmod 755 /data/mysql/log授权。
六、总结
MySQL慢查询&日志体系优化,核心是"精准配置、高效分析、精准优化"------先通过合理的参数配置,让慢查询日志"只记录有用的信息";再通过工具分析,快速定位核心慢SQL;最后结合执行计划,针对性优化(如加索引、改写SQL),形成闭环。
很多时候,数据库性能瓶颈并不是硬件不行,而是慢查询日志未配置、未分析,导致问题无法定位,小问题拖成大故障。掌握本文的配置方法和分析技巧,能帮你快速搞定MySQL慢查询问题,提升系统稳定性。
另外,建议定期(如每周)分析一次慢查询日志,提前发现潜在性能隐患,避免线上故障;同时,结合业务迭代,及时优化新增的慢SQL,形成长效运维机制。
如果你在配置、分析过程中遇到问题(如日志无法生成、工具安装失败),可以在评论区留言,我会第一时间回复排查思路!
关注我,后续持续更新MySQL实战优化、故障排查干货,助力你搞定数据库性能难题~