MySQL中通过EXPLAIN如何分析SQL的执行计划详解

 更新时间:2018年08月13日 09:41:42   作者:撸码那些事  
这篇文章主要给大家介绍了关于MySQL中通过EXPLAIN如何分析SQL的执行计划的相关资料,文中通过图文以及示例代码介绍的非常详细,对大家的学习或者工作具有一定的安康学习价值,需要的朋友们下面随着小编来一起学习学习吧

前言

在MySQL中,我们可以通过EXPLAIN命令获取MySQL如何执行SELECT语句的信息,包括在SELECT语句执行过程中表如何连接和连接的顺序。

下面分别对EXPLAIN命令结果的每一列进行说明:

.select_type:表示SELECT的类型,常见的取值有:


类型 说明
SIMPLE 简单表,不使用表连接或子查询
PRIMARY 主查询,即外层的查询
UNION UNION中的第二个或者后面的查询语句
SUBQUERY 子查询中的第一个

.table:输出结果集的表(表别名)

.type:表示MySQL在表中找到所需行的方式,或者叫访问类型。常见访问类型如下,从上到下,性能由差到最好:


ALL 全表扫描
index 索引全扫描
range 索引范围扫描
ref 非唯一索引扫描
eq_ref 唯一索引扫描
const,system 单表最多有一个匹配行
NULL 不用扫描表或索引

1、type=ALL,全表扫描,MySQL遍历全表来找到匹配行

一般是没有where条件或者where条件没有使用索引的查询语句

EXPLAIN SELECT * FROM customer WHERE active=0;

2、type=index,索引全扫描,MySQL遍历整个索引来查询匹配行,并不会扫描表

一般是查询的字段都有索引的查询语句

EXPLAIN SELECT store_id FROM customer;

3、type=range,索引范围扫描,常用于<、<=、>、>=、between等操作

EXPLAIN SELECT * FROM customer WHERE customer_id>=10 AND customer_id<=20;

注意这种情况下比较的字段是需要加索引的,如果没有索引,则MySQL会进行全表扫描,如下面这种情况,create_date字段没有加索引:

EXPLAIN SELECT * FROM customer WHERE create_date>='2006-02-13' ;

4、type=ref,使用非唯一索引或唯一索引的前缀扫描,返回匹配某个单独值的记录行

store_id字段存在普通索引(非唯一索引)

EXPLAIN SELECT * FROM customer WHERE store_id=10;

ref类型还经常会出现在join操作中:

customer、payment表关联查询,关联字段customer.customer_id(主键),payment.customer_id(非唯一索引)。表关联查询时必定会有一张表进行全表扫描,此表一定是几张表中记录行数最少的表,然后再通过非唯一索引寻找其他关联表中的匹配行,以此达到表关联时扫描行数最少。

因为customer、payment两表中customer表的记录行数最少,所以customer表进行全表扫描,payment表通过非唯一索引寻找匹配行。

EXPLAIN SELECT * FROM customer customer INNER JOIN payment payment ON customer.customer_id = payment.customer_id;

5、type=eq_ref,类似ref,区别在于使用的索引是唯一索引,对于每个索引键值,表中只有一条记录匹配

eq_ref一般出现在多表连接时使用primary key或者unique index作为关联条件。

film、film_text表关联查询和上一条所说的基本一致,只不过关联条件由非唯一索引变成了主键。

EXPLAIN SELECT * FROM film film INNER JOIN film_text film_text ON film.film_id = film_text.film_id;

6、type=const/system,单表中最多有一条匹配行,查询起来非常迅速,所以这个匹配行的其他列的值可以被优化器在当前查询中当作常量来处理

const/system出现在根据主键primary key或者 唯一索引 unique index 进行的查询

根据主键primary key进行的查询:

EXPLAIN SELECT * FROM customer WHERE customer_id =10;

根据唯一索引unique index进行的查询:

EXPLAIN SELECT * FROM customer WHERE email ='MARY.SMITH@sakilacustomer.org';

7、type=NULL,MySQL不用访问表或者索引,直接就能够得到结果

.possible_keys: 表示查询可能使用的索引

.key: 实际使用的索引

.key_len: 使用索引字段的长度

.ref: 使用哪个列或常数与key一起从表中选择行。

.rows: 扫描行的数量

.filtered: 存储引擎返回的数据在server层过滤后,剩下多少满足查询的记录数量的比例(百分比)

.Extra: 执行情况的说明和描述,包含不适合在其他列中显示但是对执行计划非常重要的额外信息

最主要的有一下三种:


Using Index 表示索引覆盖,不会回表查询
Using Where 表示进行了回表查询
Using Index Condition 表示进行了ICP优化
Using Flesort 表示MySQL需额外排序操作, 不能通过索引顺序达到排序效果

什么是ICP?

MySQL5.6引入了Index Condition Pushdown(ICP)的特性,进一步优化了查询。Pushdown表示操作下放,某些情况下的条件过滤操作下放到存储引擎。

EXPLAIN SELECT * FROM rental WHERE rental_date='2005-05-25' AND customer_id>=300 AND customer_id<=400;

在5.6版本之前:

优化器首先使用复合索引idx_rental_date过滤出符合条件rental_date='2005-05-25'的记录,然后根据复合索引idx_rental_date回表获取记录,最终根据条件customer_id>=300 AND customer_id<=400过滤出最后的查询结果(在服务层完成)。

在5.6版本之后:

MySQL使用了ICP来进一步优化查询,在检索的时候,把条件customer_id>=300 AND customer_id<=400也推到存储引擎层完成过滤,这样能够降低不必要的IO访问。Extra为Using index condition就表示使用了ICP优化。

参考

《深入浅出MySQL》

总结

以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作具有一定的参考学习价值,如果有疑问大家可以留言交流,谢谢大家对脚本之家的支持。

相关文章

  • MySQL读写分离服务配置方式

    MySQL读写分离服务配置方式

    通过Mycat代理实现MySQL的读写分离涉及准备工作、配置文件修改、权限设置、启动方式选择等关键步骤,首先,安装JDK1.8并配置环境变量;接着,对Mycat的server.xml和schema.xml进行配置,特别是schema.xml中对数据库的配置需关注
    2024-11-11
  • mysql数据库实现设置字段长度

    mysql数据库实现设置字段长度

    这篇文章主要介绍了mysql数据库实现设置字段长度,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2022-06-06
  • 关于MySQL查询语句的优化详解

    关于MySQL查询语句的优化详解

    这篇文章主要介绍了MySQL查询语句的优化方法,分别介绍了子查询优化,分页查询优化以及排序查询优化,对学习有一定的帮助,需要的小伙伴可以参考一下
    2023-04-04
  • MySQL表字段数量限制及行大小限制详情

    MySQL表字段数量限制及行大小限制详情

    这篇文章主要介绍了MySQL表字段数量限制及行大小限制详情,表的行最大的row size会限制字段数量,如果当前row size过大就不能加字段了,更多相关需要的小伙伴可以参考下面文章详情
    2022-07-07
  • mysql字段为NULL索引是否会失效实例详解

    mysql字段为NULL索引是否会失效实例详解

    有很多人对null值是否走索引感觉很疑惑,所以下面这篇文章主要给大家介绍了关于mysql字段为NULL索引是否会失效的相关资料,文中通过示例代码介绍的非常详细,需要的朋友可以参考下
    2022-05-05
  • MySQL中ADD COLUMN添加多个字段的写法实例

    MySQL中ADD COLUMN添加多个字段的写法实例

    这篇文章主要给大家介绍了关于MySQL中ADD COLUMN添加多个字段的写法实例,文中通过实例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
    2023-02-02
  • MySQL总是差八个小时该如何解决

    MySQL总是差八个小时该如何解决

    最近在用mybatis时发现,将LocalDateTime插入到数据库时时间少了8小时,下面这篇文章主要给大家介绍了关于MySQL总是差八个小时该如何解决的相关资料,文中通过示例代码介绍的非常详细,需要的朋友可以参考下
    2022-04-04
  • MySQL中MRR如何优化范围查询

    MySQL中MRR如何优化范围查询

    MySQL提供了多种优化技术以提高查询性能,其中,MRR(Multi-Range Read)优化是一种重要的查询优化技术,尤其在处理包含多个范围条件的查询时,能够显著提升查询效率,本文给大家介绍了MySQL中MRR(多范围读取)如何优化范围查询,需要的朋友可以参考下
    2024-10-10
  • MySQL redo日志写入磁盘的实现过程

    MySQL redo日志写入磁盘的实现过程

    这篇文章主要介绍了MySQL redo日志写入磁盘的实现过程,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教
    2025-06-06
  • MySQL中LAST_INSERT_ID()函数的实现

    MySQL中LAST_INSERT_ID()函数的实现

    本文主要介绍了MySQL中LAST_INSERT_ID()函数的作用和使用方法,LAST_INSERT_ID()函数用于返回上一次INSERT操作生成的自增ID,对于需要获取新插入记录的主键的场景非常重要,感兴趣的可以了解一下
    2024-10-10

最新评论