- ubuntu12.04环境下使用kvm ioctl接口实现最简单的虚拟机
- Ubuntu 通过无线网络安装Ubuntu Server启动系统后连接无线网络的方法
- 在Ubuntu上搭建网桥的方法
- ubuntu 虚拟机上网方式及相关配置详解
CFSDN坚持开源创造价值,我们致力于搭建一个资源共享平台,让每一个IT人在这里找到属于你的精彩世界.
这篇CFSDN的博客文章详解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尽量靠右,但实际运用中还是要综合考虑各个方面的.
接下来,为了演示和重现这几种连接类型,我新建了一个数据测试表,以方面更好的理解这五种类型.
1
2
3
4
5
6
7
8
|
| 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类型的查找:
1
2
3
4
5
6
|
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好,唯一可能的原因在于,按照索引扫描全表的数据是有序的。这样一来,结果不同,也就没法比效率的问题了。 如果一定要比效率,只需要获取这个表的数据并且排序便可以看出来谁比谁效率高了:
1
2
3
4
5
6
7
8
9
10
11
12
|
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',那么称这种情况为 索引覆盖; 索引覆盖意味着什么呢?想象这样一种场景,如果说一本新华字典是一张表,当然前面的索引部分(假设按照部首的索引)是这张表的索引,那么索引覆盖就相当于根据部首索引获取第一个字到最后一个字(新华字典的所有字)。我们获得了字典中所有的字,然而我们并没有查一次表,因为我们想要的都早索引中,即索引覆盖.
1
2
3
4
5
6
|
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(值允许重复) 。
1
|
alter
table
employee
add
key
I_EMPLOYEE_NAME(`
name
`);
|
接下来,在employee表中根据name查找数据的时候,mysql优化器便选择了ref的连接类型.
1
2
3
4
5
6
|
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) 。
1
2
3
4
5
6
7
|
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 是一一对应的.
1
2
3
4
5
6
7
|
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的资料请关注我其它相关文章! 。
原文链接:https://blog.csdn.net/dennis211/article/details/78170079 。
最后此篇关于详解mysql中explain的type的文章就讲到这里了,如果你想了解更多关于详解mysql中explain的type的内容请搜索CFSDN的文章或继续浏览相关文章,希望大家以后支持我的博客! 。
假设a是张量,那么有什么区别: 类型(a) a.类型 a.type() 我找不到区分这些的文档。 最佳答案 type 是 python 内置方法。 它将返回对象的类型。喜欢 torch.Tensor.
什么是 Type 1 的居民的例子?两者都不是 Type也不是Type的居民?在 Idris REPL 中进行探索时,我无法想出任何东西。 更准确地说,我正在寻找一些 x除了 Type产生以下结果:
我找到了一些资源,但我不确定我是否理解。 我找到的一些资源是: http://help.sap.com/saphelp_nw70/helpdata/en/fc/eb2ff3358411d1829f00
这两个函数原型(prototype)有什么区别? void apply1(double(f)(double)); void apply2(double(*f)(double)); 如果目标是将提供的函
http://play.golang.org/p/icQO_bAZNE 我正在练习使用堆进行排序,但是 prog.go:85: type bucket is not an expression
假设有一个泛型定义的方法信息对象,即一个方法信息对象,这样的方法Info.IsGenericMethodDefinition==TRUE:。也可以说它们也有一个泛型参数列表:。我可以使用以下命令获取该
在具有依赖类型的语言中,您可以使用 Type-in-Type 来简化语言并赋予它很多功能。这使得语言在逻辑上不一致,但如果您只对编程感兴趣而不对定理证明感兴趣,这可能不是问题。 在 Cayenne
根据 Nim 手册,变量类型是“静态类型”,而变量在内存中指向的实际值是“动态类型”。 它们怎么可能是不同的类型?我认为将错误的类型分配给变量将是一个错误。 最佳答案 import typetrait
假设您有以下结构和协议(protocol): struct Ticket { var items: [TicketItem] = [] } struct TicketItem { } prot
我正在处理一个 EF 问题,我发现它很难调试...以前,在我的系统中有一个表类型继承设置管理不同的用户类型 - 所有用户共有的一种根类型,以及大致基于使用该帐户的人员类型的几种不同的子类型。现在,我遇
这是我的 DBManager.swift import RealmSwift class DBManager { class func getAllDogs() -> [Dog] {
我正在尝试使用傅里叶校正图像中的曝光。这是我面临的错误 5 padded = np.log(padded + 1) #so we never have log of 0 6 g
关闭。这个问题是opinion-based .它目前不接受答案。 想要改进这个问题? 更新问题,以便 editing this post 可以用事实和引用来回答它. 关闭 9 年前。 Improve
请考虑以下设置: protocol MyProcotol { } class MyModel: MyProcotol { } enum Result { case success(value:
好吧,我将我的 python 项目编译成一个可执行文件,它在我的电脑上运行,但我将它发送给几个 friend 进行测试,他们都遇到了这个错误。我以前从未见过这样的错误。我使用 Nuitka 来编译代码
当我尝试训练我的模型时"ValueError: Type must be a sub-type of ndarray type"出现在 line x_norm=(np.power(x,2)).sum(
我尝试在另一个类中打断、计数然后加入对象。所以我构建协议(protocol): typealias DataBreaker = () -> [Double] typealias DataJoiner
我正在使用 VS 2015 更新 3、Angular 2.1.2、Typescript 2.0.6 有人可以澄清什么是 typings 与 npm @types 以及本月很难找到的任何其他文档吗? 或
我正在考虑从 VS2010 更改为 Mono,因此我通过 MoMA 运行我的程序集,看看我在转换过程中可能遇到多少困难。在生成的报告中,我发现我不断收到此错误: bool Type.op_Equali
主要问题 不太确定这是否可能,但由于我讨厌 Typescript 并且它使我的编码变得困难,我想我会问只是为了确定。 interface ISomeInterface { handler: ()
我是一名优秀的程序员,十分优秀!