Mysql定位慢查询

当页面加载过慢、接口压测响应时间过长(超过1s)时,很可能是因为SQL的执行时间缓慢导致。

MySQL 提供了慢查询日志功能,可以记录执行时间超过指定阈值的 SQL 语句。

1. 开启慢查询日志

配置方法

  • 临时开启(重启后失效):

    sql 复制代码
    -- 查看当前配置
    SHOW VARIABLES LIKE 'slow_query_log';
    SHOW VARIABLES LIKE 'long_query_time';
    
    -- 开启慢查询日志
    SET GLOBAL slow_query_log = ON;
    -- 设置慢查询阈值(单位:秒,这里示例为 1 秒)
    SET GLOBAL long_query_time = 1;
    -- 设置慢查询日志存储路径(可选)
    SET GLOBAL slow_query_log_file = '/var/log/mysql/mysql-slow.log';
  • 永久开启(修改配置文件 my.cnfmy.ini):

    bash 复制代码
    [mysqld]
    slow_query_log = ON
    slow_query_log_file = /var/log/mysql/mysql-slow.log
    long_query_time = 1  # 超过 1 秒的查询会被记录
    log_queries_not_using_indexes = ON  # 记录未使用索引的查询(可选)

    修改后需重启 MySQL 服务生效。

2. 分析慢查询日志

慢查询日志记录了符合条件的 SQL 语句及其执行信息,可通过以下工具分析:

直接查看日志文件

日志内容包含执行时间、锁等待时间、扫描行数等关键信息,例如:

日志文件不方便我们统计查看,通常情况下我们会使用工具来辅助。

使用 mysqldumpslow 工具

MySQL 自带的日志分析工具,可统计慢查询的频率、耗时等:

bash 复制代码
# 查看最耗时的 10 条慢查询
mysqldumpslow -s t -t 10 /var/log/mysql/mysql-slow.log

# 查看访问次数最多的 10 条慢查询
mysqldumpslow -s c -t 10 /var/log/mysql/mysql-slow.log

参数说明:-s 指定排序方式(t: 按时间,c: 按次数),-t 指定显示条数。

3.Docker安装Mysql并开启慢日志配置

环境:

centos7、mysql8.0.19

拉取 MySQL 镜像:

bash 复制代码
docker pull mysql:8.0.19

创建挂载文件目录:

bash 复制代码
# 创建本地目录(用于挂载配置、数据、日志)
mkdir -p /mysql8/{conf,data,logs}

创建配置文件和慢日志文件:

bash 复制代码
# 创建配置文件
vi /home/hl/mysql8/conf/my.cnf
# 创建慢日志
vi /home/hl/mysql8/logs/mysql-slow.log

将以下内容复制到my.cnf中:

bash 复制代码
[mysqld]
# 开启慢查询日志
slow_query_log = 1
# 慢查询日志路径(需对应容器内路径,已挂载到本地 /docker/mysql/logs)
slow_query_log_file = /var/log/mysql/mysql-slow.log
# 慢查询阈值(单位:秒,超过此值的 SQL 会被记录)
long_query_time = 1

完成上述操作后,我的目录文件如下:

创建容器:

docker run -d \
--name mysql \
-p 3306:3306 \
-e MYSQL_ROOT_PASSWORD=1234 \
-v /home/hl/mysql8/conf:/etc/mysql/conf.d \
-v /home/hl/mysql8/data:/var/lib/mysql \
-v /home/hl/mysql8/logs:/var/log/mysql \
mysql:8.0.19

查看容器是否启动:

进入容器并查看慢日志是否启用:

输入以下命令进入容器,并登录进mysql:

bash 复制代码
# 进入容器
docker exec -it mysql8 bash

# 登录 MySQL
mysql -u root -p

# 查看慢查询配置
SHOW VARIABLES LIKE 'slow_query_log';  # 应显示 ON
SHOW VARIABLES LIKE 'long_query_time'; # 应显示 1.000000
SHOW VARIABLES LIKE 'slow_query_log_file'; # 应显示日志路径

slow_query_log为ON则开启成功:

有错误参考:
关于Mysql开启慢查询日志报错:13 - Permission denied的解决方案-CSDN博客

mysqldumpslow 测试:

为了方便测试,将my.cnf的long_query_time设置为0.001,差不多每支持一条sql都会被慢日志记录下来,然后随便执行几条sql,使用**mysqldumpslow**查看:

可以清晰的查看到每条sql的执行时间、锁等待时间、扫描行数等关键信息

4.分析慢SQL

通过慢查询日志我们可以定位到慢SQL,定位到SQL后,我们就可以通过EXPLAIN 或者 DESC命令获取 MySQL 如何执行 SELECT 语句的信息:

语法:

sql 复制代码
-直接在select语句之前加上关键字 explain/desc
EXPLAIN SELECT 字段列表 FROM 表名 WHERE 条件

通过 EXPLAINEXPLAIN ANALYZE 分析 MySQL 如何执行这条 SQL,重点关注 索引使用、扫描行数、连接方式 等。

4.1 关键字段解读

执行的EXPLAIN 展示SQL信息中,我们主要关注以下这些关键字即可:

字段 含义 需关注的问题
type 访问类型(索引使用效率) 若为 ALL(全表扫描)、index(全索引扫描),说明未有效使用索引。
key 实际使用的索引 若为 NULL,说明未使用任何索引。
rows 预估扫描行数 数值越大,效率越低(尤其远大于实际返回行数 rows_sent 时)。
Extra 额外信息 出现 Using filesort(文件排序)、Using temporary(临时表)、Using where(全表扫描后过滤)均为性能隐患。
possible_keys 可能使用的索引 possible_keys 不为空但 key 为空,说明索引失效(需排查原因)。

type:

这条sql的连接的类型,性能由好到差为NULL、system、const、eq_ref、ref、range、 index、all

  • system:查询系统中的表
  • const:根据主键查询
  • eq_ref:主键索引查询或唯一索引查询
  • ref:索引查询
  • range:范围查询
  • index:索引树扫描
  • all:全盘扫描

Extra:

Extra 值 核心含义 适用场景 性能影响 典型示例
Using where 存储引擎读取数据后,在服务器层用WHERE条件过滤数据(需访问表数据行)。 无可用索引(全表扫描),或索引无法覆盖过滤条件,需回表后再过滤。 效率较低(可能全表扫描或需回表) 无索引时执行SELECT * FROM user WHERE name = 'xxx'
Using index 仅通过索引即可获取所有所需数据,无需回表(覆盖索引)。 查询的所有列都包含在索引中,且过滤条件基于索引列。 效率高(避免访问表数据,仅扫描索引) 索引包含nameage时,执行SELECT name, age FROM user WHERE name = 'xxx'
Using index condition 存储引擎层利用索引先过滤部分条件(索引下推),减少回表数据量,剩余条件在服务器层判断。 使用二级索引,过滤条件部分可通过索引字段判断(如前缀匹配),部分需回表后判断。 效率中等(减少回表数据,优于Using where 索引为(first_name, last_name)时,执行SELECT * FROM user WHERE first_name LIKE 'J%' AND last_name = 'Doe'

示例:

user_id是user表的主键,执行以下SQL语句:

主要信息如下:

4.2 分析慢SQL

通过explain展示的信息,我们可以分析该条SQL:

  • 通过key和key_len检查是否命中了索引(索引本身存在是否有失效的情况)
  • 通过type字段查看sql是否有进一步的优化空间,是否存在全索引扫描或全盘扫描
  • 通过extra建议判断,是否出现了回表的情况,如果出现了,可以尝试添加索引或修改返回字段来修复

5.相关面试问题

5.1 mysql中,如何定位慢查询?

我们可以通过MySQL中提供的慢查询日志功能进行定位。

首先,需要在cnf配置文件中自定义慢查询阈值,默认10s,我通常设置为2s。

然后,可通过查看慢查询日志或使用mysqldumpslow工具,定位到记录的慢查询SQL。

5.2 一个SQL语句执行很慢, 如何分析?

我们通常使用EXPLAIN或DESC命令可查看到执行SQL的具体信息:

通过key和key_len检查是否命中了索引,若使用了索引但是没有名称,查看索引是否失效。

通过type查看是否存在全索引扫描(index)或全盘扫描(all),若存在则可进一步优化。

通过Extra建议判断是否存在回表情况,若存在则可通过添加索引或者修改返回字段优化。

相关推荐
HashData酷克数据3 分钟前
官宣:Apache Cloudberry (Incubating) 2.0.0 发布!
数据库·开源·apache·cloudberry
秋难降4 分钟前
SQL 索引突然 “罢工”?快来看看为什么
数据库·后端·sql
TDengine (老段)33 分钟前
TDengine 时间函数 TODAY() 用户手册
大数据·数据库·物联网·oracle·时序数据库·tdengine·涛思数据
码界奇点42 分钟前
KingbaseES一体化架构与多层防护体系如何保障企业级数据库的持续稳定与弹性扩展
数据库·架构·可用性测试
悟乙己1 小时前
数据科学家如何更好地展示自己的能力
大数据·数据库·数据科学家
皆过客,揽星河1 小时前
mysql进阶语法(视图)
数据库·sql·mysql·mysql基础语法·mysql进阶语法·视图创建修改删除
tuokuac2 小时前
Redis 的相关文件作用
数据库·redis·缓存
鹧鸪云光伏与储能软件开发3 小时前
投资储能项目能赚多少钱?小程序帮你测算
运维·数据库·小程序·光伏·光伏设计软件·光伏设计
2301_779503765 小时前
MySQL主从同步--主从复制进阶
数据库·mysql
beijingliushao5 小时前
58-正则表达式
数据库·python·mysql·正则表达式