mysql中的查询计划及sql语句性能分析:explain

本文涉及的产品
云数据库 RDS MySQL,集群系列 2核4GB
推荐场景:
搭建个人博客
RDS MySQL Serverless 基础系列,0.5-2RCU 50GB
云数据库 RDS PostgreSQL,集群系列 2核4GB
简介: mysql中的查询计划及sql语句性能分析:explain

前期准备:准备相关数据表和测试数据

CREATE` `TABLE` ``employee`(`````id```int``(11)``NOT` `NULL` `AUTO_INCREMENT,```````name`````varchar``(20)``CHARACTER` `SET` `utf8 ``COLLATE` `utf8_general_ci ``NULL` `DEFAULT` `NULL``,`````dep_id```int``(11)``NULL` `DEFAULT` `NULL``,`````age```int``(11)``NULL` `DEFAULT` `NULL``,`````salary```decimal``(10,2)``NULL` `DEFAULT` `NULL``,`````cus_id```int``(11)``NULL` `DEFAULT` `NULL``,````PRIMARY` `KEY` `(`id`)USINGBTREE``)ENGINE=InnoDBAUTO_INCREMENT=9``CHARACTER` `SET` `= utf8 ``COLLATE` `= utf8_general_ci ROW_FORMAT=``Dynamic``;` `-- 测试数据``INSERT` `INTO` ``employee` ``VALUES` `(1, ``'鲁班'``, 1, 10, 1000.00, 1);``INSERT` `INTO` ``employee` ``VALUES` `(2, ``'后裔'``, 1, 20, 2000.00, 1);``INSERT` `INTO` ``employee` ``VALUES` `(3, ``'孙尚香'``, 1, 20, 2500.00, 1);``INSERT` `INTO` ``employee` ``VALUES` `(4, ``'凯'``, 4, 20, 3000.00, 1);``INSERT` `INTO` ``employee` ``VALUES` `(5, ``'典韦'``, 4, 40, 3500.00, 2);``INSERT` `INTO` ``employee` ``VALUES` `(6, ``'貂蝉'``, 6, 20, 5000.00, 1);``INSERT` `INTO` ``employee` ``VALUES` `(7, ``'孙膑'``, 6, 50, 5000.00, 1);``INSERT` `INTO` ``employee` ``VALUES` `(8, ``'蔡文姬'``, 30, 35, 4000.00, 1);` `CREATE` `TABLE` ``department` (`` ```id` ``int``(11) ``NOT` `NULL` `AUTO_INCREMENT,`` ```deptName` ``varchar``(30) ``CHARACTER` `SET` `utf8 ``COLLATE` `utf8_general_ci ``NULL` `DEFAULT` `NULL``,`` ```address` ``varchar``(40) ``CHARACTER` `SET` `utf8 ``COLLATE` `utf8_general_ci ``NULL` `DEFAULT` `NULL``,`` ``PRIMARY` `KEY` `(`id`) USING BTREE``) ENGINE = InnoDB AUTO_INCREMENT = 6 ``CHARACTER` `SET` `= utf8 ``COLLATE` `= utf8_general_ci ROW_FORMAT = ``Dynamic``;` `-- 测试数据``INSERT` `INTO` ``department` ``VALUES` `(1, ``'研发部(RD)'``, ``'2层'``);``INSERT` `INTO` ``department` ``VALUES` `(2, ``'人事部(HR)'``, ``'3层'``);``INSERT` `INTO` ``department` ``VALUES` `(3, ``'市场部(MK)'``, ``'4层'``);``INSERT` `INTO` ``department` ``VALUES` `(4, ``'后勤部(MIS)'``, ``'5层'``);``INSERT` `INTO` ``department` ``VALUES` `(5, ``'财务部(FD)'``, ``'6层'``);` `CREATE` `TABLE` ``customer` (`` ```id` ``int``(11) ``NOT` `NULL``,`` `````name``` ``varchar``(255) ``CHARACTER` `SET` `utf8 ``COLLATE` `utf8_general_ci ``NULL` `DEFAULT` `NULL``,`` ``PRIMARY` `KEY` `(`id`) USING BTREE``) ENGINE = InnoDB ``CHARACTER` `SET` `= utf8 ``COLLATE` `= utf8_general_ci ROW_FORMAT = ``Dynamic``;` `-- 测试数据``INSERT` `INTO` ``customer` ``VALUES` `(1, ``'zs'``);``INSERT` `INTO` ``customer` ``VALUES` `(2, ``'lisi'``);``INSERT` `INTO` ``customer` ``VALUES` `(3, ``'wangwu'``);

1、explain的简介

mysql中可以使用explain这个关键字来获取(查询)sql语句的查询执行计划的。使用explain关键字,可以模拟mysql优化器执行的sql语句,从而知道mysql是如何处理sql语句的通过explain可以分析查询语句或表结构的性能瓶颈

2、explain的作用

①、查看表的读取顺序

②、数据读取操作的操作类型

③、查看哪些索引可以使用

④、查看哪些索引被实际使用

⑤、查看表之间的引用

⑥、查看每张表有多少行被优化器执行

3、explain的使用方法

explain sql语句

示例:explain select * from employee;

4、explain执行计划输出中的各个列的详解

4.1、id

描述:

select查询的序列号

包含一组数字,该组数字表示查询中执行select子句或操作表的顺序

id值的三种情况如下:

①、id相同

示例如下:

-- 分析的sql语句``explain ``select` `* ``from` `employee e,department d,customer c``where` `e.dep_id = d.id ``and` `e.cus_id = c.id;

分析的结果截图:

网络异常,图片无法展示
|

从上图中可以看到,id列的值都是1。那么该条sql语句的执行顺序是由上到下,也就是说 先查询的c表 然后查询 e表 最后查询d表。

②、id不同

示例如下:

-- 分析的sql语句``EXPLAIN ``SELECT` `* ``from` `department``WHERE` `id = (``SELECT` `id ``from` `employee ``WHERE` `id=(``SELECT` `id ``from` `customer ``WHERE` `id = 1))

分析的结果截图:

网络异常,图片无法展示
|

从上图中可以看到,id列的值是1、2、3。那么该条sql语句的执行顺序是*从大到小*(由*下到上*,也就是说 id列的值是3的先执行 其次是id列的值是2 最后是id列的值是1再执行。

注意:这里都是子查询,如果是子查询,id的序号会递增,id值越大优先级越高,优先被执行。

③、id相同和不同,同时存在

示例如下:

-- 分析的sql语句``EXPLAIN ``SELECT` `* ``FROM` `department d,( ``SELECT` `* ``FROM` `employee ``GROUP` `BY` `dep_id ) t ``WHERE` `d.id = t.dep_id;

分析的结果截图:

网络异常,图片无法展示
|

从上图中可以看到,id列的值是1、1、2。那么该条sql语句的执行顺序是怎样的呢?根据上面的①和②这里应该也能猜到了。该条sql语句的执行顺序是 先执行id列的值是2的,其次执行id列的值是1的(最上面那个id列的值是1的,也就是table列的值是d),最后执行中间那个id列的值是1的。

注意:上图中有一个select_type列,其中select_type有一列的值是derived,而derived表示 衍生出来的虚表。再次说明,id值越大,优先级越高,越先执行

id列的值总结如下:

相同,顺序走(由上到下)。不同,看谁大,大的先执行。

4.2、select_type

描述:

查询类型,主要用于区别普通查询,联合查询,子查询等复杂查询。

select_type列的值主要有以下6种情况

①、SIMPLE:简单的select查询,查询中不包含子查询或者UNION

②、PRIMARY:查询中若包含任何复杂的子查询,那么最外层的查询则被标记为primary

示例截图如下:

网络异常,图片无法展示
|

③、SUBQUERY:在select或where中包含了子查询

④、DERIVED:在from列表中包含的子查询被标记为derived(衍生),把结果放在临时表当中。

示例截图如下:

网络异常,图片无法展示
|

⑤、UNION:若第二个select出现在union之后,则被标记为union。若union包含在from子句的子查询中,外层select将被标记为deriver。

⑥、UNION RESULT:从union表获取结果select。两个UNION合并的结果集在最后。

示例截图如下:

网络异常,图片无法展示
|

4.3、table

描述:

显示当前查询的数据是关于哪张表的。

4.4、partitions

描述

如果查询是基于分区表的话,会显示查询访问的分区。

4.5、type(重要)

描述

表示访问某个表的类型。更专业一点的解释就是:type代表着mysql对某个表的执行查询时的访问方法,其中type列的值就表明了这个访问方法是个啥。通过type可以知道mysql是做了全表扫描还是范围扫描等,从而知道当前的sql语句到底要不要去优化。

type列的值一般最常用的有7种,按照最好到最差来排序 分别是:system、const、eq_ref、ref、range、index、ALL。

①、system:表中只有一条记录,并且该表使用的存储引擎的统计数据是精确的,比如MyISAM、Memory,那么该表的type列的值就是system。这是const类型的特例,平时不会出现,也不用奢求将sql优化到这种级别的。

②、const:表示通过索引(主键索引或唯一索引)一次就找到了那一条数据。这里和上面那个system的区别就是 system表里面只能有一条数据,而const表示表中可能会有多条数据,但是const能直接从多条数据中直接定位到那一条数据(通过主键索引或唯一索引)。因为只匹配一行数据,所以const速度很快。

示例截图:

网络异常,图片无法展示
|

③、eq_ref:唯一性索引扫描。对于每个索引键,表中只有一条记录与之匹配。常见于主键或唯一索引扫描。还是云里雾里?没关系,上个示例截图一解释就好了。

示例截图如下:

截图1:

网络异常,图片无法展示
|

截图2:

网络异常,图片无法展示
|

employee表中有五条数据,而department表中有对应的五条数据,其中employee的id(主键索引)和department的id(主键索引)是一 一对应的,所以这里就会出现eq_ref,eq_ref也就是这个意思。

注意:eq_ref基本上很难在单表上出现,一般都是在多表的情况下才会出现eq_ref。

④、ref:非唯一性索引扫描。大白话解释一下就是:出现该连接类型的条件是, 查找条件列使用了索引而且不是使用的主键索引和唯一索引(unique),使用的是普通索引。其实,意思就是虽然使用了索引,但该索引列的值并不唯一,有重复。这样即使 使用索引快速查找到了第一条数据,仍然不能停止扫描,要进行目标值附近的小范围扫描。但它的好处是它并不需要扫全表,因为索引是有序的,即便有重复值,也是在一个非常小的范围内扫描。下面为了演示这种情形,给employee表中的age列添加一个普通的索引

ALTER` `TABLE` ``employee` ``ADD` `INDEX` ``idx_age`(`age`) USING BTREE;

然后,在employee表中根据age查找数据的时候,mysql优化器便选择了ref

示例截图如下:

网络异常,图片无法展示
|

⑤、range:指的是有范围的索引扫描,相对于index的全索引扫描,它有范围限制,因此要优于index。关于range比较容易理解,需要记住的是出现了range,则一定是基于索引的。一般就是在你的where语句中出现between,and,<,>,or,in等查询,那么type列的值就是range

⑥、index:Full Index Scan。index与All区别为index类型只遍历索引树,通常比All要快,因为索引文件通常比数据文件要小。all和index都是读全表,但index是从索引中读取,all是从硬盘当中读取。

示例截图如下:

网络异常,图片无法展示
|

⑦、ALL:将表中的所有数据进行了扫描(全表扫描),从硬盘当中读取数据。如果出现了All 且数据量非常大,那么该条sql必须去做优化的。

示例截图:

网络异常,图片无法展示
|

末尾了,说下要求:一般来说,要保证SQL查询至少达到range级别,最好能达到ref级别。

4.6、possible_keys

描述:

表示这张表中可能会用到的索引(一个或多个),查询涉及到的字段上若存在索引,则该索引将被列出,但不一定被查询实际使用到,可能自己创建了4个索引,在实际执行sql查询的时候,根据mysql内部的自动判断,只使用了3个。

4.7、key(重要)

描述:

mysql在执行的时候实际使用到的索引,如果为NULL,则没有使用索引。

其它说明:

查询中若使用了覆盖索引,则该索引仅出现在key列表中。

覆盖索引:查询的字段和建立的字段刚好吻合,这种我们称为覆盖索引。

possible_keys与key关系:前者表示理论应该用到哪些索引,后者表示实际用到了哪些索引。

4.8、key_len

描述:

表示索引中使用的字节数,可通过该列计算查询中使用的索引长度 。下面为了演示这种情形,给employee表添加一个复合索引。

ALTER` `TABLE` ``employee` ``ADD` `INDEX` ``idx_name_dep_id_age`(```name```, `dep_id`, `age`) USING BTREE;

示例截图:

网络异常,图片无法展示
|

4.9、ref

描述:

索引是否被引入到,到底引用到了哪几个索引。

这里就不写加索引的语句了,直接上几张截图看吧

网络异常,图片无法展示
|

网络异常,图片无法展示
|

网络异常,图片无法展示
|

4.10、rows

描述:

根据表的统计信息及索引选用情况,大致估算出找到所需的记录所需要扫描(读取)的行数。表有多少行被优化器查询过。没有建立索引和建立索引之后 rows所显示的数据肯定是不一样的。这里就不进行截图演示了。

4.11、filtered

描述:

满足查询的记录数量的比例,注意是百分比,不是具体记录数,值越大越好,filtered列的值依赖统计信息,并不十分准确。对于单表查询来说,这个filtered列的值没什么意义,更关注在连接查询中对应的执行计划记录的filtered列的值。关于这里的多表demo也就先不演示了。

4.12、Extra

描述:

顾名思义,Extra列是用来说明一些额外信息的,可以通过这些额外信息来更准确的理解mysql到底将如何执行给定的查询语句。mysql提供的额外信息有好几十个,这里就不一个一个介绍了,只挑一些平时常见的或者比较重要的做下说明。

①、Using filesort:专业术语成为“文件排序”。说明mysql会对数据使用一个外部的索引排序,而不是按照表内的索引顺序进行。mysql无法利用索引完成排序操作称为"文件排序",当你看到using filesort的时候,那么一定要优化该条sql语句。(得到所需结果集,需要对所有记录进行"文件排序" 出现这个 表示该条SQL语句性能较低,需要进行优化)

****

关于filesort的更多详解:filesort 并不是说通过磁盘文件进行排序,而只是告诉我们进行了一个排序操作。文件排序是通过相应的排序算法,将取得的数据在内存中进行排序。mysql需要将数据在内存中进行排序,所使用的内存区域也就是我们通过 sort_buffer_size 系统变量所设置的排序区。这个排序区是每个 Thread 独享的,所以说可能在同一时刻 在mysql中可能存在多个 sort buffer 内存区域。

filesort分两种:

双路排序:是首先根据相应的条件取出相应的排序字段和可以直接定位行数据的行指针信息,然后在sort buffer 中进行排序。排序后再吧查询字段依照行指针取出,共执行两次磁盘io。

单路排序:是一次性取出满足条件行的所有字段,然后在sort buffer中进行排序。 执行一次磁盘io。

在mysql4.1版本之前只有第一种排序算法 双路排序。第二种算法是从mysql4.1开始的改进算法,主要目的是为了减少第一次算法中需要两次访问表数据的 IO 操作,将两次变成了一次,但相应也会耗用更多的sort buffer 空间。当然,mysql4.1开始的以后所有版本同时也支持第一种算法。

典型说明:在一个没有建立索引的列上进行了order by,就会触发filesort,常见的优化方案是,在order by的列上添加索引,避免每次查询都全量排序。

Using filesort示例截图:

网络异常,图片无法展示
|

②、Using temporary:在许多查询的执行过程中,mysql可能会借助临时表来完成一些功能,比如去重、排序之类的,比如我们在执行许多包含DISTINCT、GROUP BY、UNION等子句的查询过程中,如果不能有效利用索引来完成查询,mysql很有可能寻求通过建立内部的临时表来执行查询。如果查询中使用到了内部的临时表,在执行计划的Extra列将会显示using temporary提示。当你看到using temporary的时候,那么一定要优化该条sql语句。(需要建立临时表(temporary table)来暂存中间结果,出现这个 表示该条SQL语句性能较低,通常情况下需要进行优化)

③、Useing index:表示相应的select中使用了覆盖索引,避免访问了表中的数据行,效率很好。如果同时出现了Using where 表明索引被用来执行索引键值的查找。如果没有同时出现Using where 表明索引 用来读取数据而非执行查找动作。(SQL所需要返回的所有列数据均在一棵索引树上,而无需访问实际的行记录,出现这个 表示该条SQL语句性能较好)

示例截图:

using index示例截图如下:

网络异常,图片无法展示
|

using where using index示例截图如下:

网络异常,图片无法展示
|

④、Using where:说明使用了where过滤(SQL使用了where条件过滤数据 需要需要优化该条SQL语句 需要配合explain结果中的type(连接类型)来综合判断)

⑤、Using join buffer(Block Nested Loop):在连接查询执行过程中,当sql查询语句不能有效的利用索引加快访问速度,mysql选择退而求其次,一般会为其分配一块名叫join buffer的内存块来加快查询速度,也就是我们所讲的基于块的嵌套循环算法。(需要进行嵌套循环计算 出现这个 表示该条SQL语句性能较低,需要进行优化)

打个比方:内层和外层的type均为ALL,rows均为4,需要循环进行4*4次计算。

典型说明:两个关联表join,关联字段均未建立索引,就会出现这种情况。常见的优化方案是,在关联字段上添加索引,避免每次嵌套循环计算。

⑥、impossible where:where子句中的值总是false 获取不到任何数据。出现这种提示通常情况下说明你的sql语句有误,请看情况选择是否进行修改相应的sql语句。

示例截图如下:

网络异常,图片无法展示
|

⑦、Using index condition:确实命中了索引,但不是所有的列数据都在索引树上,还需要访问实际的行记录。(出现这个 表示 该条SQL语句性能也较高,但不如Using index)

相关实践学习
如何快速连接云数据库RDS MySQL
本场景介绍如何通过阿里云数据管理服务DMS快速连接云数据库RDS MySQL,然后进行数据表的CRUD操作。
全面了解阿里云能为你做什么
阿里云在全球各地部署高效节能的绿色数据中心,利用清洁计算为万物互联的新世界提供源源不断的能源动力,目前开服的区域包括中国(华北、华东、华南、香港)、新加坡、美国(美东、美西)、欧洲、中东、澳大利亚、日本。目前阿里云的产品涵盖弹性计算、数据库、存储与CDN、分析与搜索、云通信、网络、管理与监控、应用服务、互联网中间件、移动服务、视频服务等。通过本课程,来了解阿里云能够为你的业务带来哪些帮助 &nbsp; &nbsp; 相关的阿里云产品:云服务器ECS 云服务器 ECS(Elastic Compute Service)是一种弹性可伸缩的计算服务,助您降低 IT 成本,提升运维效率,使您更专注于核心业务创新。产品详情: https://www.aliyun.com/product/ecs
相关文章
|
2月前
|
缓存 关系型数据库 MySQL
MySQL索引策略与查询性能调优实战
在实际应用中,需要根据具体的业务需求和查询模式,综合运用索引策略和查询性能调优方法,不断地测试和优化,以提高MySQL数据库的查询性能。
199 66
|
11天前
|
SQL 存储 关系型数据库
【MySQL基础篇】全面学习总结SQL语法、DataGrip安装教程
本文详细介绍了MySQL中的SQL语法,包括数据定义(DDL)、数据操作(DML)、数据查询(DQL)和数据控制(DCL)四个主要部分。内容涵盖了创建、修改和删除数据库、表以及表字段的操作,以及通过图形化工具DataGrip进行数据库管理和查询。此外,还讲解了数据的增、删、改、查操作,以及查询语句的条件、聚合函数、分组、排序和分页等知识点。
【MySQL基础篇】全面学习总结SQL语法、DataGrip安装教程
|
16天前
|
存储 Oracle 关系型数据库
索引在手,查询无忧:MySQL索引简介
MySQL 是一款广泛使用的关系型数据库管理系统,在2024年5月的DB-Engines排名中得分1084,仅次于Oracle。本文介绍MySQL索引的工作原理和类型,包括B+Tree、Hash、Full-text索引,以及主键、唯一、普通索引等,帮助开发者优化查询性能。索引类似于图书馆的分类系统,能快速定位数据行,极大提高检索效率。
48 8
|
18天前
|
SQL 关系型数据库 MySQL
MySQL 窗口函数详解:分析性查询的强大工具
MySQL 窗口函数从 8.0 版本开始支持,提供了一种灵活的方式处理 SQL 查询中的数据。无需分组即可对行集进行分析,常用于计算排名、累计和、移动平均值等。基本语法包括 `function_name([arguments]) OVER ([PARTITION BY columns] [ORDER BY columns] [frame_clause])`,常见函数有 `ROW_NUMBER()`, `RANK()`, `DENSE_RANK()`, `SUM()`, `AVG()` 等。窗口框架定义了计算聚合值时应包含的行。适用于复杂数据操作和分析报告。
59 11
|
22天前
|
存储 关系型数据库 MySQL
mysql怎么查询longblob类型数据的大小
通过本文的介绍,希望您能深入理解如何查询MySQL中 `LONG BLOB`类型数据的大小,并结合优化技术提升查询性能,以满足实际业务需求。
84 6
|
29天前
|
SQL 存储 缓存
MySQL进阶突击系列(02)一条更新SQL执行过程 | 讲透undoLog、redoLog、binLog日志三宝
本文详细介绍了MySQL中update SQL执行过程涉及的undoLog、redoLog和binLog三种日志的作用及其工作原理,包括它们如何确保数据的一致性和完整性,以及在事务提交过程中各自的角色。同时,文章还探讨了这些日志在故障恢复中的重要性,强调了合理配置相关参数对于提高系统稳定性的必要性。
|
28天前
|
SQL 关系型数据库 MySQL
MySQL 高级(进阶) SQL 语句
MySQL 提供了丰富的高级 SQL 语句功能,能够处理复杂的数据查询和管理需求。通过掌握窗口函数、子查询、联合查询、复杂连接操作和事务处理等高级技术,能够大幅提升数据库操作的效率和灵活性。在实际应用中,合理使用这些高级功能,可以更高效地管理和查询数据,满足多样化的业务需求。
110 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;