用 Explain 命令分析 MySQL 的 SQL 执行

本文涉及的产品
云数据库 RDS MySQL,集群系列 2核4GB
推荐场景:
搭建个人博客
RDS MySQL Serverless 基础系列,0.5-2RCU 50GB
RDS MySQL Serverless 高可用系列,价值2615元额度,1个月
简介: 在上一篇文章《MySQL常见加锁场景分析》中,我们聊到行锁是加在索引上的,但是复杂的 SQL 往往包含多个条件,涉及多个索引,找出 SQL 执行时使用了哪些索引对分析加锁场景至关重要。

title: 用 Explain 命令分析 MySQL 的 SQL 执行
tags: mysql
abbrlink: 755443b5

date: 2020-06-02 22:06:48

在上一篇文章《MySQL常见加锁场景分析》中,我们聊到行锁是加在索引上的,但是复杂的 SQL 往往包含多个条件,涉及多个索引,找出 SQL 执行时使用了哪些索引对分析加锁场景至关重要。

比如下面这样的 SQL:

mysql> delete from t1 where id = 1 or val = 1

其中 id 和 val 都是索引,那么执行时使用到了哪些索引,加了哪些锁呢?为此,我们需要使用 explain 来获取 MySQL 执行这条 SQL 的执行计划。

什么是执行计划呢?简单来说,就是 SQL 在数据库中执行时的表现情况,通常用于 SQL 性能分析、优化和加锁分析等场景,执行过程会在 MySQL 查询过程中由解析器,预处理器和查询优化器共同生成。

MySQL 查询过程

如果能搞清楚 MySQL 是如何优化和执行查询的,不仅对优化查询一定会有帮助,还可以通过分析使用到的索引来判断最终的加锁场景。

下图是MySQL执行一个查询的过程。实际上每一步都比想象中的复杂,尤其优化器,更复杂也更难理解。本文只给予简单的介绍。

mysql_sql_execute

MySQL查询过程如下:

  • 客户端发送一条查询给服务器。
  • 服务器先检查查询缓存,如果命中了缓存,则立刻返回存储在缓存中的结果。否则进入下一阶段。
  • 服务器端进行SQL解析、预处理,再由优化器生成对应的执行计划。
  • MySQL根据优化器生成的执行计划,再调用存储引擎的API来执行查询。
  • 将结果返回给客户端。

执行计划

MySQL会解析查询,并创建内部数据结构(解析树),并对其进行各种优化,包括重写查询、决定表的读取顺序、选择合适的索引等。

用户可通过关键字提示(hint)优化器,从而影响优化器的决策过程。也可以通过 explain 了解 数据库是如何进行优化决策的,并提供一个参考基准,便于用户重构查询和数据库表的 schema、修改数据库配置等,使查询尽可能高效。

下面,我们依次介绍 explain 中相关输出参数,并以实际例子解释这些参数的含义。

select_type

查询数据的操作类型,有如下

  • simple 简单查询,不包含子查询或 union,如下图所示,就是最简单的查询语句。

select_type_simple

  • primary 是 SQL 中包含复杂的子查询,此时最外层查询标记为该值。
  • derived 是 SQL 中 from 子句中包含的子查询被标记为该值,MySQL 会递归执行这些子查询,把结果放在临时表。下图展示了上述两种类型。

select_type_primary

  • subquery 是 SQL 在 select 或者 where 里包含的子查询,被标记为该值。

select_type_subquery

  • dependent subquery:子查询中的第一个 select,取决于外侧的查询,一般是 in 中的子查询。

select_type_d_subquery

  • union 是 SQL 在出现在 union 关键字之后的第二个 select ,被标记为该值;若 union 包含在 from 的子查询中,外层select 被标记为 derived。
  • union result 从 union 表获取结果的 select。下图展示了 union 和 union result 的 SQL 案例。

select_type_union

  • dependent union 也是 union 关键字之后的第二个或者后边的那个 select 语句,和 dependent subquery 一样,取决于外面的查询。

select_type_d_union

type

表的连接类型,其性能由高到低排列为 system,const,eq_ref,ref,range,index 和 all。

  • system 表示表只有一行记录,相当于系统表。如下图所示,因为 from 的子查询派生的表只有一行数据,所以 primary 的表连接类型为 system。

select_type_primary

  • const 通过索引一次就找到,只匹配一行数据,用于常数值比较PRIMARY KEY 或者 UNIQUE索引。

select_type_simple

  • eq_ref 唯一性索引扫描,对于每个索引键,表中只有一条记录与之匹配,常用于主键或唯一索引扫描。对于每个来自前边的表的行组合,从该表中读取一行。它是除了 const 类型外最好的连接类型。

如下图所示,对表 t1 查询的 type 是 ALL,表示全表扫描,然后 t1 中每一行数据都来跟 t2.id 这个主键索引进行对比,所以 t2 表的查询就是 eq_ref。

ref

  • ref 非唯一性索引扫描,返回匹配某个单独值的所有行,和 eq_ref 的区别是索引是非唯一索引,具体案例如下所示。

type_ref

  • range 只检查给定范围的行,使用一个索引来选择行,当使用 =, between, >, <, 和 in 等操作符,并使用常数比较关键列时。如下图所示,其中 id 为唯一索引,而 val 是非唯一索引。

range

  • index 与 ALL 类型类似,唯一区别就是只遍历索引树读取索引值,比 ALL 读取所有数据行要稍微快一些,因为索引文件通常比数据文件小。这里涉及 MySQL 的索引覆盖
  • ALL 全表扫描,通常情况下性能很差,应该避免。

possible_keys,key 和 key_len

possible_key 列指出 MySQL 可能使用哪个索引在该表中查找。如果该列为 NULL,则没有使用相关索引。需要检查 where 子句条件来创建合适的索引提高查询效率。

key 列显示 MySQL 实际决定使用的索引。如果没有选择索引,则值为 NULL。

key_len 显示 MySQL 决定使用索引的长度。如果键为 NULL,则本列也为 NULL,使用的索引长度,在保证精确度的情况下,越短越好。因为越短,索引文件越小,需要的 I/O次数也越少。

keys_ref

由上图可以看出,对于 select * from t2 where id = 1 or val = 1这个语句,可以使用 PRIMARY 或者 idx_t2_val 索引,实际使用了 idx_t2_val 索引,索引的长度为5。

这些其实是我们分析加锁场景最为关心的字段,后续文章会具体讲解如何根据这些字段和其他工具一起判断复杂 SQL 到底加了哪些锁。

ref

ref 列表示使用其他表的哪个列或者常数来从表中选择行。如下图所示,从 t2 读取数据时,要判断 t2.id = t1.id,所以 ref 就是 mysql.t1.id

ref

rows 和 filtered

rows 列显示 MySQL 认为它执行查询时必须检查的行数。

filtered 列表明了 SQL 语句执行后返回结果的行数占读取行数的百分比,值越大越好。MySQL 会使用 Table Filter 来读取出来的行数据进行过滤,理论上,读取出来的行等于返回结果的行数时效率最高,过滤的比率越多,效率越低。

filtered

如上图所示,t1表中有三条数据,rows 为 3,表示所有行都要读取出来。根据 val = 3 这个 table filter 过滤,只返回一行数据,所以 filtered 比例为33.33%,

extra

包含不适合在其他列中显示但十分重要的额外信息。常见的值如下

  • using index 表示 select 操作使用了覆盖索引,避免了访问表的数据行,效率不错。
  • using where 子句用于限制哪一行。也就是读取数据后使用了 Table Filter 进行过滤。

如下图所示,因为 id 和 val 都是有索引的,所以 select * 也是可以直接使用覆盖索引读取数据,所以 extra 中有 using index。而因为只使用 val 索引读取了3行数据,还是通过 where 子句进行过滤,filtered为 55%,所以 extra 中使用了 using where。

keys_ref

  • using filesort MySQL 会对数据使用一个外部的索引排序,而不是按照表内的索引顺序进行读取,若出现该值,应该优化 SQL 语句。如下图所示,其中 val 列没有索引,所以无法使用索引顺序排序读取。

filesort

  • using temporary 使用临时表保存中间结果,比如,MySQL 在对查询结果排序时使用临时表,常用于 order by 和 group by,如果出现该值,应该优化 SQL。根据我的经验,group by 一个无索引列,或者ORDER BY 或 GROUP BY 的列不是来自JOIN语句序列的第一个表,就会产生临时表。
  • using join buffer 使用连接缓存。如下图所示,展示了连接缓存和临时表。关于连接缓存的内容,大家可以自行查阅,后续有时间在写文章解释。

temporary

  • distinct 发现第一个匹配后,停止为当前的行组合搜索更多的行

后记

通过 explain 了解到 SQL 的执行计划后,我们不仅可以了解 SQL 执行时使用的索引,判断加锁场景,还可以针对其他信息对 SQL 进行优化分析,比如将 type 类型从 index 优化到 ref 等。

[个人博客,欢迎来玩]

相关实践学习
如何快速连接云数据库RDS MySQL
本场景介绍如何通过阿里云数据管理服务DMS快速连接云数据库RDS MySQL,然后进行数据表的CRUD操作。
全面了解阿里云能为你做什么
阿里云在全球各地部署高效节能的绿色数据中心,利用清洁计算为万物互联的新世界提供源源不断的能源动力,目前开服的区域包括中国(华北、华东、华南、香港)、新加坡、美国(美东、美西)、欧洲、中东、澳大利亚、日本。目前阿里云的产品涵盖弹性计算、数据库、存储与CDN、分析与搜索、云通信、网络、管理与监控、应用服务、互联网中间件、移动服务、视频服务等。通过本课程,来了解阿里云能够为你的业务带来哪些帮助 &nbsp; &nbsp; 相关的阿里云产品:云服务器ECS 云服务器 ECS(Elastic Compute Service)是一种弹性可伸缩的计算服务,助您降低 IT 成本,提升运维效率,使您更专注于核心业务创新。产品详情: https://www.aliyun.com/product/ecs
相关文章
|
23天前
|
SQL 关系型数据库 MySQL
深入解析MySQL的EXPLAIN:指标详解与索引优化
MySQL 中的 `EXPLAIN` 语句用于分析和优化 SQL 查询,帮助你了解查询优化器的执行计划。本文详细介绍了 `EXPLAIN` 输出的各项指标,如 `id`、`select_type`、`table`、`type`、`key` 等,并提供了如何利用这些指标优化索引结构和 SQL 语句的具体方法。通过实战案例,展示了如何通过创建合适索引和调整查询语句来提升查询性能。
121 9
|
16天前
|
SQL 存储 关系型数据库
【MySQL基础篇】全面学习总结SQL语法、DataGrip安装教程
本文详细介绍了MySQL中的SQL语法,包括数据定义(DDL)、数据操作(DML)、数据查询(DQL)和数据控制(DCL)四个主要部分。内容涵盖了创建、修改和删除数据库、表以及表字段的操作,以及通过图形化工具DataGrip进行数据库管理和查询。此外,还讲解了数据的增、删、改、查操作,以及查询语句的条件、聚合函数、分组、排序和分页等知识点。
【MySQL基础篇】全面学习总结SQL语法、DataGrip安装教程
|
1月前
|
SQL 存储 缓存
MySQL进阶突击系列(02)一条更新SQL执行过程 | 讲透undoLog、redoLog、binLog日志三宝
本文详细介绍了MySQL中update SQL执行过程涉及的undoLog、redoLog和binLog三种日志的作用及其工作原理,包括它们如何确保数据的一致性和完整性,以及在事务提交过程中各自的角色。同时,文章还探讨了这些日志在故障恢复中的重要性,强调了合理配置相关参数对于提高系统稳定性的必要性。
|
1月前
|
SQL 关系型数据库 MySQL
MySQL 高级(进阶) SQL 语句
MySQL 提供了丰富的高级 SQL 语句功能,能够处理复杂的数据查询和管理需求。通过掌握窗口函数、子查询、联合查询、复杂连接操作和事务处理等高级技术,能够大幅提升数据库操作的效率和灵活性。在实际应用中,合理使用这些高级功能,可以更高效地管理和查询数据,满足多样化的业务需求。
143 3
|
1月前
|
SQL 关系型数据库 MySQL
MySQL导入.sql文件后数据库乱码问题
本文分析了导入.sql文件后数据库备注出现乱码的原因,包括字符集不匹配、备注内容编码问题及MySQL版本或配置问题,并提供了详细的解决步骤,如检查和统一字符集设置、修改客户端连接方式、检查MySQL配置等,确保导入过程顺利。
|
1月前
|
SQL 存储 关系型数据库
MySQL进阶突击系列(01)一条简单SQL搞懂MySQL架构原理 | 含实用命令参数集
本文从MySQL的架构原理出发,详细介绍其SQL查询的全过程,涵盖客户端发起SQL查询、服务端SQL接口、解析器、优化器、存储引擎及日志数据等内容。同时提供了MySQL常用的管理命令参数集,帮助读者深入了解MySQL的技术细节和优化方法。
|
1月前
|
SQL Oracle 关系型数据库
SQL(MySQL)
SQL语言是指结构化查询语言,是一门ANSI的标准计算机语言,用来访问和操作数据库。 数据库包括SQL server,MySQL和Oracle。(语法大致相同) 创建数据库指令:CRATE DATABASE websecurity; 查看数据库:show datebase; 切换数据库:USE websecurity; 删除数据库:DROP DATABASE websecurity;
|
2月前
|
SQL 关系型数据库 MySQL
MySql5.6版本开启慢SQL功能-本次采用永久生效方式
MySql5.6版本开启慢SQL功能-本次采用永久生效方式
48 0
|
2月前
|
SQL 关系型数据库 MySQL
mysql编写sql脚本:要求表没有主键,但是想查询没有相同值的时候才进行插入
mysql编写sql脚本:要求表没有主键,但是想查询没有相同值的时候才进行插入
38 0
|
17天前
|
存储 Oracle 关系型数据库
数据库传奇:MySQL创世之父的两千金My、Maria
《数据库传奇:MySQL创世之父的两千金My、Maria》介绍了MySQL的发展历程及其分支MariaDB。MySQL由Michael Widenius等人于1994年创建,现归Oracle所有,广泛应用于阿里巴巴、腾讯等企业。2009年,Widenius因担心Oracle收购影响MySQL的开源性,创建了MariaDB,提供额外功能和改进。维基百科、Google等已逐步替换为MariaDB,以确保更好的性能和社区支持。掌握MariaDB作为备用方案,对未来发展至关重要。
44 3