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的解释的更多相关文章

  1. MySQL中explain的type类型

    |  ALL              |  全表扫描 |  index            |  索引全扫描 |  range            |  索引范围扫描,常用语<,<= ...

  2. mysql中explain的用法

    mysql中explain的用法 最近在做性能测试中经常遇到一些数据库的问题,通常使用慢查询日志可以找到执行效果比较差的sql,但是仅仅找到这些sql是不行的,我们需要协助开发人员分析问题所在,这就经 ...

  3. 详解MySQL中EXPLAIN解释命令

    Explain 结果解读与实践   基于 MySQL 5.0.67 ,存储引擎 MyISAM .   注:单独一行的"%%"及"`"表示分隔内容,就象分开“第一 ...

  4. MySQL中EXPLAIN解释命令详解

    MySQL中的explain命令显示了mysql如何使用索引来处理select语句以及连接表.explain显示的信息可以帮助选择更好的索引和写出更优化的查询语句. 1.EXPLAIN的使用方法:在s ...

  5. MySQL中EXPLAIN解释命令 查看索引是否生效

    explain显示了mysql如何使用索引来处理select语句以及连接表.可以帮助选择更好的索引和写出更优化的查询语句. 使用方法,在select语句前加上explain就可以了: 如: expla ...

  6. mysql中explain详解

    explain语法 有两种用法: 1.EXPLAIN tbl_name    2.EXPLAIN [EXTENDED] SELECT select_options 为了更好的说明它,我们需要建两张表, ...

  7. Mysql中explain命令查看语句执行概况

    Mysql中可以使用explain命令查看查询语句的执行方式,使用方法举例:explain + 查询语句 例如:explain select * from user_info 几个重要的字段说明: t ...

  8. MySQL使用explain时各字段解释

    1.id select查询的序列号,包含一组数字,表示查询中执行select子句或操作表的顺序 三种情况: (1)id相同,执行顺序由上至下 id相同,执行顺序由上至下 此例中 先执行where 后的 ...

  9. MySQL中explain语句的使用

    一.概述 在 MySQL 中,我们可以使用慢查询日志或者 show processlist 命令等方式定位到执行耗时较长的 SQL 语句,在这之后我们可以通过 EXPLAIN或者 DESC 命令获取 ...

随机推荐

  1. 【微信小程序项目实践总结】30分钟从陌生到熟悉

    前言 我们之前对小程序做了基本学习: 1. 微信小程序开发07-列表页面怎么做 2. 微信小程序开发06-一个业务页面的完成 3. 微信小程序开发05-日历组件的实现 4. 微信小程序开发04-打造自 ...

  2. Python input保证输入为int类型

    t = float(input("t(℃)="))

  3. .NET运行时中的监测和可观测性

    今年5月份的时候研究分布式追踪的问题知道了的拦截方式比较零散, 刚好8月份的时候看到这篇文章,这个文章总结的比较完整.存档了很久,趁今天有空翻译给大家.原文地址,校验:张蘅水 .NET是一个托管运行时 ...

  4. SLAM+语音机器人DIY系列:(三)感知与大脑——1.ydlidar-x4激光雷达

    摘要 在我的想象中机器人首先应该能自由的走来走去,然后应该能流利的与主人对话.朝着这个理想,我准备设计一个能自由行走,并且可以与人语音对话的机器人.实现的关键是让机器人能通过传感器感知周围环境,并通过 ...

  5. powdesingner 更新数据库表结构

    1.连接数据库 2更新数据库表结构

  6. 69道Spring面试题和答案,简单明了无套路

    目录 Spring 概述 依赖注入 Spring beans Spring注解 Spring数据访问 Spring面向切面编程(AOP) Spring MVC Spring 概述 1. 什么是spri ...

  7. 第二章 Linux目录学习

    Linux 目录结构相对windows来说更简单,Linux 目录 以 斜杠 / 为根目录,其整体结构是以/为根的树状结构. 使用 tree -L 1 查看1级目录结构 /bin 常用的二进制命令目录 ...

  8. js调用百度地图接口绘制任意多边形并获取每个点的经纬度等

    来自:https://blog.csdn.net/u013239236/article/details/52213977 侵删 <!DOCTYPE html> <html> & ...

  9. VS Code怎样设置成中文

    打开 VS Code Ctrl + Shift +p打开搜索框 搜索框内输入Configure Display Language 回车 修改代码中“locale”后面引号内内容为zh-CH 重新启动V ...

  10. Failure sending mail: The user or group name 'xxx\xxxx' is not recognized.Mail will not be resent

      一批Reporting Service报表的订阅突然报如下错误: Failure sending mail: The user or group name 'xxx\xxxx' is not re ...