【MySQL | 第五篇】 MySQL 性能分析:如何查询慢 SQL

一、前言

在面试和项目开发中,慢 SQL 是比较常见的问题。

如果一条 SQL 执行时间过长,轻则导致接口响应变慢,重则导致请求超时。要是大量慢 SQL 同时出现,还可能把数据库连接池占满,最终影响整个系统的正常访问。

今天我们就来回答并深入学习这个问题:怎么把慢 SQL 找出来

二、查看 SQL 执行频次

SQL 执行频次,指的是某类 SQL 语句在数据库中被执行的次数。

比如在一个系统中,select 执行得特别多,而 insertupdate 相对较少,那么我们在做性能优化时,就可以优先关注查询语句。因为这类 SQL 执行频率高,优化之后的收益也更明显。

在 MySQL 中,可以通过下面的命令查看常见 SQL 的执行频次:

sql 复制代码
show global status like 'Com_______';

这里的 global 表示查看全局统计信息(要注意global重启后失效),如果只想查看当前会话的统计信息,也可以写成:

sql 复制代码
show session status like 'Com_______';

Com_______ 中有 7 个下划线。这里的下划线是 like 语句中的通配符,用来匹配 Com_selectCom_insertCom_update 这类状态变量。

常见字段如下:

-- 事务相关

com_begin: 执行 begin 操作的次数 com_commit: 执行 commit 操作的次数 com_rollback: 执行 rollback 操作的次数
-- dml 操作(最常用) com_select: 执行 select 操作的次数 com_insert: 执行 insert 操作的次数 com_update: 执行 update 操作的次数 com_delete: 执行

delete 操作的次数
-- ddl 操作 com_create_table: 执行 create table 的次数 com_drop_table: 执行 drop table 的次数 com_alter_table: 执行 alter table 的次数
-- 表维护 com_repair: 执行 repair table 的次数 com_optimize: 执行 optimize table 的次数
-- 权限操作

com_grant: 执行 grant 的次数

com_revoke: 执行 revoke 的次数
-- show 相关

com_show_databases: 执行 show databases 的次数

com_show_tables: 执行 show tables 的次数

com_show_status: 执行 show status 的次数

com_show_variables: 执行 show variables 的次数

com_show_processlist: 执行 show processlist 的次数
-- binlog

com_binlog: 执行 binlog 操作的次数
-- 其他

com_change_db: 执行 use database 的次数

com_kill: 执行 kill 的次数

例如,我们一次查看所有常用的包括提交删除插入事务,查询,更新的频率

通过这一步,我们可以先大概判断系统的 SQL 访问特点:到底是查询多,还是写入多,后续优化时也会更有方向。

三、开启慢查询日志

如果说执行频次是帮我们判断"哪类 SQL 执行得多",那么慢查询日志就是帮我们找到"哪些 SQL 执行得慢"。

MySQL 的慢查询日志会记录执行时间超过指定阈值的 SQL 语句。这个阈值由 long_query_time 参数控制,单位是秒,默认值通常是 10 秒。

1. 查看慢查询日志是否开启

先查看慢查询日志的开关状态(ON为开启,OFF为关闭):

sql 复制代码
show variables like 'slow_query_log';

2. 临时开启慢查询日志

可以通过下面的命令临时开启慢查询日志:

sql 复制代码
set global slow_query_log = 'on';

也可以写成:

sql 复制代码
set global slow_query_log = 1;

需要注意的是,这种方式是运行时修改,MySQL 重启之后可能会失效。如果希望长期生效,需要写到 MySQL 配置文件中。

3. 设置慢查询时间阈值

查看当前慢查询时间阈值:

sql 复制代码
show variables like 'long_query_time';

例如我们希望 SQL 执行时间超过 2 秒就被记录下来,可以设置:

sql 复制代码
set global long_query_time = 2;

如果只想在当前会话中测试,也可以使用:

sql 复制代码
set session long_query_time = 2;

这里要注意一点:slow_query_log 是控制慢查询日志是否开启,而 long_query_time 是控制超过多少秒才算慢查询。两个参数的作用不一样。

4. 查看慢查询日志文件位置

这个时候可能会有一个问题:慢查询日志开启之后,生成的日志文件在哪里?

更直接的方式是查看 slow_query_log_file

sql 复制代码
show variables like 'slow_query_log_file';

如果想查看 MySQL 的数据目录,也可以使用:

sql 复制代码
select @@datadir;

查询结果就是 MySQL 的数据目录地址。慢查询日志文件一般会在这个目录下,文件名中通常会带有 slow.log

5. 测试慢查询日志是否生效

为了测试慢查询日志是否真的生效,可以执行一条耗时 SQL:

sql 复制代码
select sleep(3);

如果我们把 long_query_time 设置成了 2 秒,那么这条 SQL 执行 3 秒,就会被记录到慢查询日志中。

然后找到后缀为 slow.log的文件,打开之后就可以看到慢查询记录。

慢查询日志中比较重要的信息一般包括:

字段 含义
Query_time SQL 实际执行耗时
Lock_time 等待锁的时间
Rows_sent 返回给客户端的行数
Rows_examined 扫描过的行数
SQL 语句 具体被记录下来的慢 SQL

其中我们最需要关注的是 Query_timeRows_examined

如果 Query_time 很长,说明 SQL 执行时间确实比较久。如果 Rows_examined 很大,说明 MySQL 为了得到结果扫描了大量数据,这种情况通常就需要继续用 explain 分析执行计划。

四、使用 show profile 查看 SQL 耗时

慢查询日志可以帮助我们找到慢 SQL,但如果我们想继续看一条 SQL 在执行过程中具体耗时在哪里,可以使用 show profile

先查看 profiling 是否开启:

sql 复制代码
select @@profiling;

如果结果为 0,说明默认是关闭的。可以通过下面的命令开启:

sql 复制代码
set profiling = 1;

然后执行需要分析的 SQL,再查看 SQL 执行记录:

sql 复制代码
show profiles;

如果想查看某一条 SQL 的详细耗时阶段,可以继续执行:

sql 复制代码
show profile for query 1;

这里的 1show profiles 结果中的 Query_ID

show profile 更适合学习阶段观察 SQL 执行过程。在实际项目或生产环境中,更推荐结合慢查询日志、explain、监控工具以及 Performance Schema 一起分析。

五、使用 explain 查看执行计划

找到慢 SQL 之后,下一步就要分析它为什么慢。

这时最常用的工具就是 explain。它可以告诉我们 MySQL 准备怎么执行这条 SQL,比如有没有走索引、预计扫描多少行、访问类型是什么等。

基本语法如下:

sql 复制代码
explain select 字段列表
from 表名
where 条件;

例如:

sql 复制代码
explain select *
from emp
where username = 'Tom';

1. explain 的输出格式

在 MySQL 8.0 中,explain 支持多种输出格式,比如传统表格格式、树形格式和 JSON 格式。

如果你的环境中看到的是树形结果,类似下面这样:

sql 复制代码
explain format=tree
select 字段列表
from 表名
where 条件;

树形格式更适合看执行步骤之间的层级关系。

如果想看到我们平时更常见的表格字段,可以使用传统格式:

sql 复制代码
explain format=traditional
select 字段列表
from 表名
where 条件;

也可以使用 JSON 格式查看更完整的信息:

sql 复制代码
explain format=json
select 字段列表
from 表名
where 条件;

对于初学阶段来说,先掌握 format=traditional 的表格字段就够用了。

2. explain 常见字段说明

explain format=traditional 的结果中,常见字段如下:

字段 含义 重点怎么看
id 查询中 select 的编号 id 相同通常从上往下看,id 不同一般值越大越先执行
select_type 查询类型 常见有 SIMPLEPRIMARYSUBQUERYUNION
table 当前访问的表 表示这一行执行计划分析的是哪张表
partitions 匹配到的分区 没有使用分区表时通常为 NULL
type 访问类型 非常重要,用来判断访问表的方式好不好
possible_keys 可能使用的索引 优化器认为这条 SQL 可能用到哪些索引
key 实际使用的索引 如果为 NULL,说明没有使用索引
key_len 使用索引的长度 表示 MySQL 实际使用了索引中的多少字节
ref 索引比较对象 表示索引列和哪个列或常量进行比较
rows 预计扫描行数 估算值,越大通常说明扫描数据越多
filtered 条件过滤百分比 要结合 rows 一起看,不能单独判断好坏
Extra 额外信息 会显示 Using whereUsing indexUsing filesort 等补充信息

3. type 字段怎么看

explain 中,type 是非常关键的字段,它表示 MySQL 访问表的方式。

常见访问类型可以简单按下面顺序理解:

text 复制代码
system > const > eq_ref > ref > range > index > ALL

一般来说,越靠左性能越好,越靠右性能越差。

type 含义 说明
system 系统表或只有一行数据的表 这种情况比较少见
const 通过主键或唯一索引精确匹配一行 性能很好
eq_ref 多表连接时,通过主键或唯一索引匹配唯一一行 常见于关联查询
ref 使用普通索引进行查询 可能匹配多行
range 使用索引进行范围查询 例如 ><BETWEENIN
index 扫描整个索引树 比全表扫描好一些,但仍然可能扫描很多数据
ALL 全表扫描 如果数据量大,就需要重点关注

这里还可能看到 NULLNULL 一般表示查询不需要访问表,比如直接执行:

sql 复制代码
explain select 1;

这种情况比较特殊,不需要放到常规的性能优劣顺序里理解。

4. Extra 字段怎么看

Extra 字段是执行计划中的补充信息,也很值得关注。

Extra 信息 含义 是否需要关注
Using where MySQL 在存储引擎取出数据后,还需要根据 where 条件过滤 正常情况,结合 rows 一起看
Using index 使用了覆盖索引,不需要回表查询 通常是比较好的情况
Using temporary 使用了临时表 需要关注,常见于 group byorder by
Using filesort MySQL 需要额外排序 需要关注,可能和索引设计有关

其中 Using temporaryUsing filesort 在数据量比较大时要重点分析,因为它们可能会带来额外的内存或磁盘开销。

5. 分析 explain 时的思路

explain 时,不需要一上来就把所有字段背下来,可以先抓住几个重点:

  1. key 是否为 NULL

    如果 keyNULL,说明这条 SQL 没有使用索引,需要继续分析查询条件、索引设计以及字段类型是否匹配。

  2. type 是否为 ALL

    如果 typeALL,说明 MySQL 做了全表扫描。小表问题不大,但如果是大表,就很可能是慢 SQL 的原因。

  3. rows 是否过大

    rows 表示 MySQL 预计要扫描多少行。它是估算值,不一定完全准确,但可以用来判断扫描范围是否过大。

  4. Extra 中是否出现 Using temporaryUsing filesort

    如果出现这两个信息,说明 SQL 可能发生了临时表或额外排序,需要重点检查 order bygroup by 以及相关索引。

  5. possible_keyskey 是否一致

    possible_keys 表示可能使用的索引,key 表示最终实际使用的索引。如果 possible_keys 有值,但 keyNULL,说明优化器最终没有选择索引,这时就要继续分析条件写法、数据量、索引区分度等问题。

六、总结

这一篇主要学习了如何查询慢 SQL,而不是直接进入 SQL 优化。

整体流程可以总结为:

  1. 先用 show status 查看 SQL 执行频次,判断系统中哪类 SQL 最常见
  2. 再开启慢查询日志,通过 slow_query_log 和 long_query_time找到真正执行慢的 SQL
  3. 如果想看单条 SQL 的耗时阶段,可以使用 show profile
  4. 最后使用 explain 查看执行计划,重点关注 typekeyrowsExtra

今天我们把慢SQL查询学习完毕,下篇我们将会讲到索引与SQL优化,这基本是相关联的也是面试的重点内容

相关推荐
lee_curry1 小时前
tomcat+springmvc+spring源码流通过程
java·spring·tomcat·springmvc
w1wi1 小时前
【兼职】边学边练的AI网站
java·人工智能·ai·ai编程·ai写作
basketball6161 小时前
C++进阶:1. 引用折叠规则
java·开发语言·c++
404号扳手1 小时前
Java 进阶知识(七)
java·后端
承渊政道1 小时前
【MySQL数据库学习】(MySQL数据类型)
数据库·学习·mysql·ubuntu·bash·数据库开发·数据库系统
梦想的颜色1 小时前
MySQL 三大日志:Redo Log、Undo Log 和 Binlog 完全解析
数据库·mysql·数据库架构
小马爱打代码1 小时前
Spring框架:介绍和快速入门
java·后端·spring
糖果店的幽灵1 小时前
LangChain 1.3 完全教程:从入门到精通-Part 7: Documents(文档处理)
java·python·langchain
Java_2017_csdn1 小时前
Java 策略模式(Strategy Pattern)-(三)
java·开发语言·servlet