MySQL慢查询日志开启与使用:找到那些偷偷变慢的SQL

 更新时间:2026年06月24日 09:12:01   作者:花生了什么事o  
本文旨在帮助数据库入门学习者掌握 MySQL 慢查询日志的使用方法,从开启配置、日志字段解读、mysqldumpslow工具使用,到配合 EXPLAIN 做深度分析,带你建立一套完整的慢 SQL 排查链路

慢查询日志是什么

慢查询日志是 MySQL 提供的一个功能,它会把执行时间超过指定阈值的 SQL 语句记录到文件里。

有了慢查询日志,你就不用一行一行翻代码去猜哪条 SQL查询较慢可能存在问题,直接看日志就可以找到问题SQL。

MySQL 默认是关闭慢查询日志的,因为记录日志本身有性能开销,所以生产环境通常只在排查问题时临时开启,或者设置一个相对严格的阈值(比如 1 秒),只记录真正有问题的 SQL。

开启慢查询日志

查看当前状态

-- 查看慢查询日志是否开启
SHOW VARIABLES LIKE 'slow_query_log';

-- 查看阈值(单位:秒)
SHOW VARIABLES LIKE 'long_query_time';

-- 查看日志文件路径
SHOW VARIABLES LIKE 'slow_query_log_file';

正常情况下,slow_query_log 的值是 OFFlong_query_time 默认是 10 秒。10 秒太宽松了,生产环境一般设成 1 秒甚至 0.5 秒,主要还是取决于业务场景。

临时开启(当前会话生效)

-- 开启慢查询日志
SET GLOBAL slow_query_log = 'ON';

-- 设置阈值为 1 秒(超过 1 秒的 SQL 才记录)
SET GLOBAL long_query_time = 1;

-- 可选:记录没有使用索引的 SQL
SET GLOBAL log_queries_not_using_indexes = 'ON';

SET GLOBAL 设置的参数在 MySQL 重启后会失效,下次启动还是用配置文件里的值。

永久开启(修改配置文件)

编辑 MySQL 的配置文件 my.cnf(Linux)或 my.ini(Windows),在 [mysqld] 段落下添加:

[mysqld]
# 开启慢查询日志
slow_query_log = 1

# 慢查询阈值:1 秒
long_query_time = 1

# 日志文件路径(可以自定义)
slow_query_log_file = /var/log/mysql/slow.log

# 可选:记录没有使用索引的 SQL
log_queries_not_using_indexes = 1

修改之后重启 MySQL,或者执行 SET GLOBAL 命令让配置立即生效。

一个小技巧log_queries_not_using_indexes 这个参数很实用。它会把所有没走索引的 SQL 都记录下来,不管执行时间多长。这类 SQL 在数据量小的时候可能跑得很快,但随着数据增长会越来越慢,属于"定时炸弹",有了这个功能就可以早点发现早点处理。

慢查询日志长什么样

开启之后,我们来制造一条慢查询,看看日志长什么样。

先准备一张测试表和一些数据:

CREATE TABLE user_order (
    id BIGINT PRIMARY KEY AUTO_INCREMENT,
    user_id BIGINT NOT NULL,
    order_no VARCHAR(32) NOT NULL,
    amount DECIMAL(10, 2),
    status VARCHAR(20),
    create_time DATETIME,
    INDEX idx_user_id (user_id)
) ENGINE=InnoDB;

-- 插入 100 万条测试数据
DELIMITER //
CREATE PROCEDURE generate_orders(IN n INT)
BEGIN
    DECLARE i INT DEFAULT 0;
    WHILE i < n DO
        INSERT INTO user_order (user_id, order_no, amount, status, create_time)
        VALUES (
            FLOOR(RAND() * 10000),
            CONCAT('ORD', LPAD(i, 10, '0')),
            ROUND(RAND() * 1000, 2),
            ELT(FLOOR(RAND() * 3) + 1, 'pending', 'paid', 'cancelled'),
            DATE_SUB(NOW(), INTERVAL FLOOR(RAND() * 365) DAY)
        );
        SET i = i + 1;
    END WHILE;
END //
DELIMITER ;

CALL generate_orders(1000000);

现在执行一条故意不走索引的查询:

-- 对 status 做模糊查询,status 上没有索引
SELECT * FROM user_order WHERE status LIKE 'p%' ORDER BY create_time DESC LIMIT 50;

等它跑完(可能要几秒),然后去日志文件里找找看。日志文件的路径可以用 SHOW VARIABLES LIKE 'slow_query_log_file' 查看。

一条典型的慢查询日志长这样:

# Time: 2026-06-21T14:32:05.123456+08:00
# User@Host: root[root] @ localhost []  Id:    42
# Query_time: 2.356789  Lock_time: 0.000123 Rows_sent: 50  Rows_examined: 1000000
SET timestamp=1718946725;
SELECT * FROM user_order WHERE status LIKE 'p%' ORDER BY create_time DESC LIMIT 50;

逐行解读:

字段含义重点关注
TimeSQL 执行的时间点定位问题发生的时刻
User@Host执行 SQL 的用户和来源排查是不是某个服务在搞事
Query_timeSQL 执行总耗时(秒)核心指标,越小越好
Lock_time等待锁的时间(秒)如果很大,说明有锁竞争
Rows_sent返回给客户端的行数和 LIMIT 对比,看有没有多返回
Rows_examined扫描的行数核心指标,越大说明越低效
SQL 语句实际执行的 SQL拿去 EXPLAIN 分析

最该关注的两个数字:Query_time 和 Rows_examined。

Query_time 告诉你这条 SQL 到底慢不慢,Rows_examined 告诉你它为什么慢。如果 Rows_examined 是 100 万,但 Rows_sent 只有 50,说明 MySQL 扫了 100 万行才挑出 50 条——这就是典型的索引缺失或索引失效。

mysqldumpslow:日志分析工具

日志文件看几条还行,但如果慢查询很多,一条条翻就太低效了。MySQL 自带了一个日志分析工具 mysqldumpslow,可以帮我们做汇总统计。

# 按执行时间排序,取前 10 条最慢的
mysqldumpslow -s t -t 10 /var/log/mysql/slow.log

# 按扫描行数排序,取前 10 条
mysqldumpslow -s r -t 10 /var/log/mysql/slow.log

# 按执行次数排序,取前 10 条
mysqldumpslow -s c -t 10 /var/log/mysql/slow.log

参数说明:

参数含义
-s t按总执行时间排序(默认)
-s r按扫描总行数排序
-s c按执行次数排序
-s l按锁等待时间排序
-t N只显示前 N 条
-g "pattern"只匹配包含指定字符串的 SQL

输出结果类似:

Count: 125  Time=2.36s (295s)  Lock=0.00s (0.15s)  Rows=50.0 (6250), root[root]@localhost
  SELECT * FROM user_order WHERE status LIKE 'S' ORDER BY create_time DESC LIMIT N

这一行告诉我们:这条 SQL 在统计时段内执行了 125 次,平均耗时 2.36 秒,累计耗时 295 秒,平均扫描行数 6250 条。

Count 大的说明是高频 SQL,Time 大的说明是耗时大户。 如果一条 SQL Count 和 Time 都大,那它就是性能优化的第一优先级。

配合 EXPLAIN 做深度分析

慢查询日志帮你找到了"嫌疑人",但要定罪还需要充分的证据。所以在拿到日志里的 SQL 后,我们继续用 EXPLAIN 看看它的执行计划:

EXPLAIN SELECT * FROM user_order WHERE status LIKE 'p%' ORDER BY create_time DESC LIMIT 50;

输出可能是:

+----+------+-------+------+---------+------+----------+-----------------------------+
| id | type | key   | ref  | rows    | filtered | Extra                              |
+----+------+-------+------+---------+----------+------------------------------------+
|  1 | ALL  | NULL  | NULL | 1000000 |    33.33 | Using where; Using filesort        |
+----+------+-------+------+---------+----------+------------------------------------+

四个危险信号:

  1. type = ALL:全表扫描,没走索引
  2. key = NULL:没有可用索引
  3. rows = 1000000:扫描了 100 万行
  4. Extra = Using filesort:额外排序

和日志里的 Rows_examined = 1000000 对上了。问题很明确:status 列没有索引,MySQL 只能全表扫描。

优化方案:给 status 加索引,或者改成联合索引 (status, create_time) 同时覆盖过滤和排序:

ALTER TABLE user_order ADD INDEX idx_status_time (status, create_time);

再查一次 EXPLAIN:

+----+-------+----------------+------+---------+------+----------+-------+
| id | type  | key            | ref  | rows    | filtered | Extra       |
+----+-------+----------------+------+---------+----------+-------------+
|  1 | range | idx_status_time| NULL |  333333 |   100.00 | Using where |
+----+-------+----------------+------+---------+----------+-------------+

type 从 ALL 变成了 range,rows 从 100 万降到了 33 万,Using filesort 也没了。执行时间从 2 秒多降到几百毫秒。

慢查询日志负责"发现问题",EXPLAIN 负责"定位原因",两者配合才是完整的调优链路。

常见问题排查清单

拿到慢查询日志后,按照这个清单逐项检查:

现象可能原因排查方法
Rows_examined 远大于 Rows_sent索引缺失或索引失效EXPLAIN 看 type 和 key
Query_time 大但 Rows_examined 不大锁等待、IO 等待关注 Lock_time,检查是否有表锁
同一条 SQL 时快时慢执行计划不稳定EXPLAIN 看是否有多个候选索引
日志里出现大量相同 SQL慢查询集中在某几张表mysqldumpslow -s c 统计频次
某个时间段集中出现慢查询定时任务、批量导入检查 Time 字段的时间分布
Lock_time 很大有事务长时间未提交检查 SHOW ENGINE INNODB STATUS

一个实用的排查流程:

小结

慢查询日志是 MySQL 性能排查的起点。它帮你从海量 SQL 中筛选出真正有问题的那些,附上执行时间、扫描行数等关键指标,让你的调优工作有的放矢。

从实际操作来看,慢查询日志 + EXPLAIN 是一对黄金搭档。前者负责"发现",后者负责"诊断"。发现问题是第一步,解决问题是第二步,在后端面试之中遇到“mysql如何调优”这个问题,我们就可以采用这个思路进行回答。在实际工作生产环境中,我们依然使用这个思路进行实际的排查优化。

以上就是MySQL慢查询日志开启与使用:找到那些偷偷变慢的SQL的详细内容,更多关于MySQL慢查询日志的资料请关注脚本之家其它相关文章!

相关文章

  • MySQL迁移KingbaseESV8R2的实现步骤

    MySQL迁移KingbaseESV8R2的实现步骤

    本文主要介绍了MySQL迁移KingbaseESV8R2的实现步骤,文中通过示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2022-02-02
  • mysql 8.0.11安装配置方法图文教程

    mysql 8.0.11安装配置方法图文教程

    这篇文章主要为大家详细介绍了mysql 8.0.11安装配置方法图文教程,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2018-08-08
  • DBeaver连接mysql数据库图文教程(超详细)

    DBeaver连接mysql数据库图文教程(超详细)

    本文主要介绍了DBeaver连接mysql数据库图文教程,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2023-07-07
  • Centos7 下Mysql5.7.19安装教程详解

    Centos7 下Mysql5.7.19安装教程详解

    这篇文章主要介绍了Centos7 下Mysql5.7.19安装教程详解,小编认为非常不错,特此分享到脚本之家平台,需要的朋友参考下吧
    2017-09-09
  • SQL调优实战之让查询效率飙升10倍的实用技巧

    SQL调优实战之让查询效率飙升10倍的实用技巧

    在数据洪流时代,企业每1毫秒的查询延迟都可能造成百万级营收损失,本文将结合18个真实案例与28段代码示例,揭示从索引设计到执行计划分析的完整优化链路,助你掌握让查询效率提升10倍的核心方法,实现降本增效的技术跃迁
    2026-01-01
  • MySQL中使用SQL语句查看某个表的编码方法

    MySQL中使用SQL语句查看某个表的编码方法

    下面小编就为大家带来一篇MySQL中使用SQL语句查看某个表的编码方法。小编觉得挺不错的,现在就分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2016-11-11
  • 一文深入探究MySQL自增锁

    一文深入探究MySQL自增锁

    MySQL的自增锁是指在使用自增主键(Auto Increment)时,为了保证唯一性和正确性,系统会对自增字段进行加锁,这样可以确保同时插入多条记录时,每条记录都能够获得唯一的自增值,本将和大家一起深入探究MySQL自增锁,需要的朋友可以参考下
    2023-08-08
  • MySQL如何比较时间(datetime)大小

    MySQL如何比较时间(datetime)大小

    这篇文章主要介绍了MySQL如何比较时间(datetime)大小,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2022-11-11
  • mysql查询当天的数据

    mysql查询当天的数据

    这篇文章主要介绍了mysql查询当天的数据,第一种数量小的时候用,数据量稍微起来巨慢,第二种速度快,但是最好配合复合索引来查,避免全表扫描,需要的朋友可以参考下
    2023-08-08
  • mysql 8.0.16 Win10 zip版本安装配置图文教程

    mysql 8.0.16 Win10 zip版本安装配置图文教程

    这篇文章主要为大家详细介绍了mysql 8.0 Win10 zip版本安装配置图文教程,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2019-06-06

最新评论