详解mysql中explain的type

导语:

很多情况下,有很多人用各种select语句查询到了他们想要的数据后,往往便以为工作圆满结束了。
这些事情往往发生在一些学生亦或刚入职场但之前又没有很好数据库基础的小白身上,但所谓闻道有先后,只要我们小白好好学习,天天向上,还是很靠谱的。

当一个sql查询语句被写出来之后,其实你的工作只完成了一小半,接下来更重要的工作是评估你自己写的sql的质量与效率。mysql为我们提供了很有用的辅助武器explain,它向我们展示了mysql接收到一条sql语句的执行计划。根据explain返回的结果我们便可以知道我们的sql写的怎么样,是否会造成查询瓶颈,同时根据结果不断的修改调整查询语句,从而完成sql优化的过程。

虽然 explain返回的结果项很多,这里我们只关注三种,分别是type,key,rows。其中key表明的是这次查找中所用到的索引,rows是指这次查找数据所扫描的行数(这里可以先这样理解,但实际上是内循环的次数)。而type则是本文要详细记录的连接类型,前两项重要而且简单,无需多说。

type -- 连接类型

type意味着类型,这里的type官方全称是“join type”,意思是“连接类型”,这样很容易给人一种错觉觉得必须需要俩个表以上才有连接类型。事实上这里的连接类型并非字面那样的狭隘,它更确切的说是一种数据库引擎查找表的一种方式,在《高性能mysql》一书中作者更是觉得称呼它为访问类型更贴切一些。

mysql5.7中type的类型达到了14种之多,这里只记录和理解最重要且经常遇见的六种类型,它们分别是all,index,range,ref,eq_ref,const。从左到右,它们的效率依次是增强的。撇开sql的具体应用环境以及其他因素,你应当尽量优化你的sql语句,使它的type尽量靠右,但实际运用中还是要综合考虑各个方面的。

接下来,为了演示和重现这几种连接类型,我新建了一个数据测试表,以方面更好的理解这五种类型。

| employee | CREATE TABLE `employee` (
 `rec_id` int(11) NOT NULL AUTO_INCREMENT,
 `no` varchar(10) NOT NULL,
 `name` varchar(20) NOT NULL,
 `position` varchar(20) NOT NULL,
 `age` varchar(2) NOT NULL,
 PRIMARY KEY (`rec_id`)
) ENGINE=InnoDB AUTO_INCREMENT=6 DEFAULT CHARSET=utf8 |

all

这便是所谓的“全表扫描”,如果是展示一个数据表中的全部数据项,倒是觉得也没什么,如果是在一个查找数据项的sql中出现了all类型,那通常意味着你的sql语句处于一种最原生的状态,有很大的优化空间。
为什么这么说呢?因为all是一种非常暴力和原始的查找方法,非常的耗时而且低效。用all去查找数据就好比这样的一个情形:S学校有俩万人,我告诉你你给我找到小明,然后你怎么做呢!你当然是把全校俩万人挨个找一遍,即使你很幸运第一个人便找到了小明,但是你仍然不能停下,因为你无法确认是否有另外一个小明存在,直到你把俩万人找完为止。所以,基本所有情况,我们都要避免这样类型的查找,除非你不得不这样做。
以employee表为例,下面一种情形便是all类型的查找:

mysql> explain select * from employee where `no` = '20150001';
+----+-------------+----------+------+---------------+------+---------+------+------+-------------+
| id | select_type | table  | type | possible_keys | key | key_len | ref | rows | Extra    |
+----+-------------+----------+------+---------------+------+---------+------+------+-------------+
| 1 | SIMPLE   | employee | ALL | NULL     | NULL | NULL  | NULL |  5 | Using where |
+----+-------------+----------+------+---------------+------+---------+------+------+-------------+

这是因为no列既不是主键也不是索引,因此只能采用全表扫描来查找目标no。

index

这种连接类型只是另外一种形式的全表扫描,只不过它的扫描顺序是按照索引的顺序。这种扫描根据索引然后回表取数据,和all相比,他们都是取得了全表的数据,而且index要先读索引而且要回表随机取数据,因此index不可能会比all快(取同一个表数据),但为什么官方的手册将它的效率说的比all好,唯一可能的原因在于,按照索引扫描全表的数据是有序的。这样一来,结果不同,也就没法比效率的问题了。
如果一定要比效率,只需要获取这个表的数据并且排序便可以看出来谁比谁效率高了:

mysql> explain select * from employee order by `no` ;
+----+-------------+----------+------+---------------+------+---------+------+------+----------------+
| id | select_type | table  | type | possible_keys | key | key_len | ref | rows | Extra     |
+----+-------------+----------+------+---------------+------+---------+------+------+----------------+
| 1 | SIMPLE   | employee | ALL | NULL     | NULL | NULL  | NULL |  5 | Using filesort |
+----+-------------+----------+------+---------------+------+---------+------+------+----------------+
mysql> explain select * from employee order by rec_id ;
+----+-------------+----------+-------+---------------+---------+---------+------+------+-------+
| id | select_type | table  | type | possible_keys | key   | key_len | ref | rows | Extra |
+----+-------------+----------+-------+---------------+---------+---------+------+------+-------+
| 1 | SIMPLE   | employee | index | NULL     | PRIMARY | 4    | NULL |  5 | NULL |
+----+-------------+----------+-------+---------------+---------+---------+------+------+-------+

上面可以看出,根据no列排序的连接类型是all型的,但是注意extra列是用到了排序(Using filesort),而根据rec_id列排序的连接类型是index,而且得到的结果自然是有序的,不许额外的排序。可能正是因为这个缘故,index的效率比all高,但注意这需要相同的条件才成立(既需要排序)。

如果连接类型为type,而且extra列中的值为‘Using index',那么称这种情况为 索引覆盖;
索引覆盖意味着什么呢?想象这样一种场景,如果说一本新华字典是一张表,当然前面的索引部分(假设按照部首的索引)是这张表的索引,那么索引覆盖就相当于根据部首索引获取第一个字到最后一个字(新华字典的所有字)。我们获得了字典中所有的字,然而我们并没有查一次表,因为我们想要的都早索引中,即索引覆盖。

mysql> explain select rec_id from employee ;
+----+-------------+----------+-------+---------------+---------+---------+------+------+-------------+
| id | select_type | table  | type | possible_keys | key   | key_len | ref | rows | Extra    |
+----+-------------+----------+-------+---------------+---------+---------+------+------+-------------+
| 1 | SIMPLE   | employee | index | NULL     | PRIMARY | 4    | NULL |  5 | Using index |
+----+-------------+----------+-------+---------------+---------+---------+------+------+-------------+

上例获取的rec_id刚好为索引列,因此无需回表取数据。

range

range指的是有范围的索引扫描,相对于index的全索引扫描,它有范围限制,因此要优于index。关于range比较容易理解,需要记住的是出现了range,则一定是基于索引的。同时除了显而易见的between,and以及'>','<'外,in和or也是索引范围扫描。

ref

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

 alter table employee add key I_EMPLOYEE_NAME(`name`); 

接下来,在employee表中根据name查找数据的时候,mysql优化器便选择了ref的连接类型。

mysql> explain select * from employee where `name` = '张三';
+----+-------------+----------+------+----------------+----------------+---------+-------+------+-----------------------+
| id | select_type | table  | type | possible_keys | key      | key_len | ref  | rows | Extra         |
+----+-------------+----------+------+----------------+----------------+---------+-------+------+-----------------------+
| 1 | SIMPLE   | employee | ref | I_EMPLOYEE_NAM | I_EMPLOYEE_NAM | 62   | const |  1 | Using index condition |
+----+-------------+----------+------+----------------+----------------+---------+-------+------+-----------------------+

ref_eq

ref_eq 与 ref相比牛的地方是,它知道这种类型的查找结果集只有一个?什么情况下结果集只有一个呢!那便是使用了主键或者唯一性索引进行查找的情况,比如根据学号查找某一学校的一名同学,在没有查找前我们就知道结果一定只有一个,所以当我们首次查找到这个学号,便立即停止了查询。这种连接类型每次都进行着精确查询,无需过多的扫描,因此查找效率更高,当然列的唯一性是需要根据实际情况决定的。
在单个表中,曾尝试了很多方法想出现ref_eq的连接类型,然而很多时候出现的都是const,因此不得不随手连接了一张表得到了想要的连接类型,该表的建表代买为。(博主比较懒,连接了两个没有关系的表,o(╯□╰)o)

CREATE TABLE `score` (
 `rec_id` INT(11) NOT NULL AUTO_INCREMENT,
 `stu_id` INT(11) NOT NULL,
 `mark` INT(11) NOT NULL DEFAULT '0',
 PRIMARY KEY (`rec_id`),
 UNIQUE KEY `UK_SCORE_STU_ID` (`stu_id`)
) ENGINE=INNODB AUTO_INCREMENT=6 DEFAULT CHARSET=utf8

employee表中有五条数据,score表中有对应的五条数据,其中employee的rec_id 和score的stu_id 是一一对应的。

mysql> explain select ep.name,sc.mark from employee ep,score sc where ep.rec_id = sc.stu_id;
+----+-------------+-------+--------+-----------------+---------+---------+-----------------+------+-------+
| id | select_type | table | type  | possible_keys  | key   | key_len | ref       | rows | Extra |
+----+-------------+-------+--------+-----------------+---------+---------+-----------------+------+-------+
| 1 | SIMPLE   | sc  | ALL  | UK_SCORE_STU_ID | NULL  | NULL  | NULL      |  5 | NULL |
| 1 | SIMPLE   | ep  | eq_ref | PRIMARY     | PRIMARY | 4    | my_db.sc.stu_id |  1 | NULL |
+----+-------------+-------+--------+-----------------+---------+---------+-----------------+------+-------+

上面就可以看到score表是全表扫描的类型,rows=5代表外层表循环了五次(因为有五条数据),但是employee表的rows怎么是1,怎么可能?刚开始也是很疑惑,这与mysql的查询原理息息相关,rows实际反映的是查询的内循环数,针对外层的每一条数据匹配,employee的确一枪就可以命中,因此rows为1。

const

通常情况下,如果将一个主键放置到where后面作为条件查询,mysql优化器就能把这次查询优化转化为一个常量。至于如何转化以及何时转化,这个取决于优化器。

总结

explain 就像一面镜子,有事没事写完sql记得explain一下。同时,在写文章也发现,有很多东西和细节,想要明白清楚,也是没有那么简单的,需要对操作系统以及数据库的底层查询和运行原理要有一个清楚的理解。同时type的几种类型几乎都是基于索引之上的,因此需要对索引有个深入的了解,而且explain的结果可以指导我们什么时候加索引,什么时候不加索引,从而让我们更好的使用索引。

以上就是详解mysql中explain的type的详细内容,更多关于mysql中explain的type的资料请关注我们其它相关文章!

(0)

相关推荐

  • MySQL中执行计划explain命令示例详解

    前言 explain命令是查看查询优化器如何决定执行查询的主要方法. 这个功能有局限性,并不总会说出真相,但它的输出是可以获取的最好信息,值得花时间去了解,因为可以学习到查询是如何执行的. 调用EXPLAIN 在select之前添加explain,mysql会在查询上设置一个标记,当执行查询计划时,这个标记会使其返回关于执行计划中每一步的信息,而不是执行它. 它会返回一行或多行信息,显示出执行计划中的每一部分和执行次序. 这是一个简单的explain效果: 在查询中每个表在输出只有一行,如果查询

  • mysql之explain使用详解(分析索引)

    explain显示了mysql如何使用索引来处理select语句以及连接表.可以帮助选择更好的索引和写出更优化的查询语句. 使用方法,在select语句前加上explain就可以了,如: explain select * from statuses_status where id=11; explain列的解释 table:显示这一行的数据是关于哪张表的 type:这是重要的列,显示连接使用了何种类型.从最好到最差的连接类型为const.eq_reg.ref.range.indexhe和all

  • MYSQL 性能分析器 EXPLAIN 用法实例分析

    本文实例讲述了MYSQL 性能分析器 EXPLAIN 用法.分享给大家供大家参考,具体如下: 使用方法: EXPLAIN SELECT * FROM user; 环境和数据准备 -- 查看 MySQL 版本 SELECT VERSION(); -- MySQL 提供什么存储引擎 SHOW ENGINES; -- 查看默认存储引擎 SHOW VARIABLES LIKE '%storage_engine%'; 输出结果: id:输出的是整数,用来标识整个 SQL 的执行顺序.id 如果相同,从上往

  • 详解MySQL中EXPLAIN解释命令及用法讲解

    1,情景描述:同事教我在mysql中用explain,于是查看了一番返回内容的含义 2,现就有用处的内容做如下记录: 1,explain显示了mysql如何使用索引来处理select语句以及连接表.可以帮助选择更好的索引和写出更优化的查询语句. 使用方法,在select语句前加上explain就可以了: explain select count(DISTINCT uc_userid) as user_login from user_char_daily_gameapp_11 where uc_d

  • Mysql深入探索之Explain执行计划详析

    前言 如何写出效率高的SQL语句,提到这必然离不开Explain执行计划的分析,至于什么是执行计划,如何写出高效率的SQL,本篇文章将会一一介绍. 执行计划 执行计划是数据库根据 SQL 语句和相关表的统计信息作出的一个查询方案,这个方案是由查询优化器自动分析产生的. 使用explain关键字可以模拟优化器执行 SQL 查询语句,从而知道 MySQL 是如何处理你的 SQL 语句的,分析你的 select 语句或是表结构的性能瓶颈,让我们知道 select 效率低下的原因,从而改进我们的查询.

  • MySql中如何使用 explain 查询 SQL 的执行计划

    explain命令是查看查询优化器如何决定执行查询的主要方法. 这个功能有局限性,并不总会说出真相,但它的输出是可以获取的最好信息,值得花时间去了解,因为可以学习到查询是如何执行的. 1.什么是MySQL执行计划 要对执行计划有个比较好的理解,需要先对MySQL的基础结构及查询基本原理有简单的了解. MySQL本身的功能架构分为三个部分,分别是 应用层.逻辑层.物理层,不只是MySQL ,其他大多数数据库产品都是按这种架构来进行划分的. 应用层,主要负责与客户端进行交互,建立链接,记住链接状态,

  • MySQL如何基于Explain关键字优化索引功能

    explain显示了MySQL如何使用索引来处理select语句以及连接表.可以帮助选择更好的索引和写出更优化的查询语句.简单讲,它的作用就是分析查询性能. explain关键字的使用方法很简单,就是把它放在select查询语句的前面. mysql查看是否使用索引,简单的看type类型就可以.如果它是all,那说明这条查询语句遍历了所有的行,并没有使用到索引. 比如:explain select * from company_info where cname like '%小%' explain

  • Mysql中explain作用详解

    一.MYSQL的索引 索引(Index):帮助Mysql高效获取数据的一种数据结构.用于提高查找效率,可以比作字典.可以简单理解为排好序的快速查找的数据结构. 索引的作用:便于查询和排序(所以添加索引会影响where 语句与 order by 排序语句). 在数据之外,数据库还维护着满足特定查找算法的数据结构,这些数据结构以某种方式引用数据.这样就可以在这些数据结构上实现高级查找算法.这些数据结构就是索引. 索引本身也很大,不可能全部存储在内存中,所以索引往往以索引文件的形式存储在磁盘上. 我们

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

    前言 在MySQL中,我们可以通过EXPLAIN命令获取MySQL如何执行SELECT语句的信息,包括在SELECT语句执行过程中表如何连接和连接的顺序. 下面分别对EXPLAIN命令结果的每一列进行说明: .select_type:表示SELECT的类型,常见的取值有: 类型 说明 SIMPLE 简单表,不使用表连接或子查询 PRIMARY 主查询,即外层的查询 UNION UNION中的第二个或者后面的查询语句 SUBQUERY 子查询中的第一个 .table:输出结果集的表(表别名) .t

  • 详解mysql中explain的type

    导语: 很多情况下,有很多人用各种select语句查询到了他们想要的数据后,往往便以为工作圆满结束了. 这些事情往往发生在一些学生亦或刚入职场但之前又没有很好数据库基础的小白身上,但所谓闻道有先后,只要我们小白好好学习,天天向上,还是很靠谱的. 当一个sql查询语句被写出来之后,其实你的工作只完成了一小半,接下来更重要的工作是评估你自己写的sql的质量与效率.mysql为我们提供了很有用的辅助武器explain,它向我们展示了mysql接收到一条sql语句的执行计划.根据explain返回的结果

  • 详解MySQL中的pid与socket

    socket文件:当用Unix域套接字方式进行连接时需要的文件. pid文件:MySQL实例的进程ID文件. 1.pid-file介绍 MySQL 中的 pid 文件记录的是当前 mysqld 进程的 pid ,pid 亦即 Process ID .可以通过 pid-file 参数来配置 pid 文件路径及文件名,如果未指定此变量,则 pid 文件默认名为 host_name.pid ,存放的路径默认放在 MySQL 的数据目录. 建议指定 pid 文件名及路径,pid 目录权限要对 mysql

  • 详解MySQL中timestamp和datetime时区问题导致做DTS遇到的坑

    目录 MySQL中如何表示当前时间? 结论 验证 坑 MySQL中如何表示当前时间? 其实,表达方式还是蛮多的,汇总如下: Data Type "Zero" Value DATE '0000-00-00' TIME '00:00:00' DATETIME '0000-00-00 00:00:00' TIMESTAMP '0000-00-00 00:00:00' YEAR 0000 datetime和timestamp这两种类型都是用于表示YYYY-MM-DD HH:MM:SS 这种年月

  • 详解MySQL中的存储过程和函数

    目录 区别 优点 创建储存函数和过程 储存过程 储存函数 查看储存过程 操作 变量 赋值 变量例子 定义条件和处理过程 条件 处理程序 游标 流程控制语句 储存过程和函数就是数据器将一些处理封装起来,调用 区别 调用储存过程只需要使用CALL,然后指定储存名称和参数,参数可以是IN.OUT和INOUT 调用储存函数只需要使用SELECT,指定名称和参数,储存函数必须有返回值,参数只能是IN 优点 良好的封装性 应用程序和SQL逻辑分离 让SQL也具有处理能力 减少网络交互 能够提高系统性能 降低

  • 详解MySQL中Order By排序和filesort排序的原理及实现

    目录 1.Order By原理 2.filesort排序算法 3.优化排序 1.Order By原理 MySQL的Order By操作用于排序,并且会有多种不同的排序算法,他们的性能都是不一样的. 假设有一个表,建表的sql如下: CREATE TABLE `obtest` ( `id` BIGINT NOT NULL AUTO_INCREMENT, `a` VARCHAR ( 100 ) NOT NULL, `b` VARCHAR ( 100 ) NOT NULL, `c` VARCHAR (

  • 详解mysql中的冗余和重复索引

    mysql允许在相同列上创建多个索引,无论是有意还是无意,mysql需要单独维护重复的索引,并且优化器在优化查询的时候也需要逐个地进行考虑,这会影响性能. 重复索引是指的在相同的列上按照相同的顺序创建的相同类型的索引,应该避免这样创建重复索引,发现以后也应该立即删除.但,在相同的列上创建不同类型的索引来满足不同的查询需求是可以的. CREATE TABLE test( ID INT NOT NULL PRIMARY KEY, A INT NOT NULL, B INT NOT NULL, UNI

  • 详解mysql中的静态变量的作用

    详解mysql中的静态变量的作用 使用静态变量 static variable 示例代码: function Test() { $a = 0; echo $a; $a++; } 本函数没什么用处,因为每次调用时都会将 $a 的值设为 0 并输出 "0".将变量加一的 $a++ 没有作用,因为一旦退出本函数则变量 $a 就不存在了 示例代码: function Test(){ static $a = 0; echo $a; $a++; } 每次调用 Test() 函数都会输出 $a 的值

  • 详解 Mysql中的delimiter定义及作用

    初学mysql时,可能不太明白delimiter的真正用途,delimiter在mysql很多地方出现,比如存储过程.触发器.函数等. 学过oracle的人,再来学mysql就会感到很奇怪,百思不得其解. 其实就是告诉mysql解释器,该段命令是否已经结束了,mysql是否可以执行了. 默认情况下,delimiter是分号(;) . 在命令行客户端中,如果有一行命令以分号结束,那么回车后,mysql将会执行该命令.如输入下面的语句 mysql> select * from test_table;

  • 详解MySQL中的数据类型和schema优化

    最近在学习MySQL优化方面的知识.本文就数据类型和schema方面的优化进行介绍. 1. 选择优化的数据类型 MySQL支持的数据类型有很多,而如何选择出正确的数据类型,对于性能是至关重要的.以下几个原则能够帮助确定数据类型: 更小的通常更好 应尽可能使用可以正确存储数据的最小数据类型,够用就好.这样将占用更少的磁盘.内存和缓存,而在处理时也会耗时更少. 简单就好 当两种数据类型都能胜任一个字段的存储工作时,选择简单的那一方,往往是最好的选择.例如整型和字符串,由于整型的操作代价要小于字符,所

随机推荐