id
如果是子查询 id会依次递增,id的值越大,优先值越高,越先被执行
select_type 参数
-
SIMPLE:
简单的select语句(查询中不包含子查询和UNION); -
PRIMARY
:查询中若包含任何复杂的子部分,最外层(即最后加载的那一个)会被标记为PRIMARY -
DERIVED:
在from列表中的包含的子查询被标记为DERIVED(衍生),Mysql会递归执行这些子查询,并把结果放在临时的表里面 -
SUBQURY:
在select 或者where 列中包含的子查询 -
UNION:
若第二个select出现在UNION之后, 就会被标记为UNION;若UNION包含在FROM查询的字句当中,则外层SElECT会被标记为DERIVED;
-
UNION RESULT:
从UNION表获取结果的SELECT。
table
显示该行数据是关于哪张表的
type
显示查询使用何种类型(即找到所需数据使用的扫描方式 官网解释:连接类型the join type
),效率从好到坏依次为System>const>eq_ref>ref>range>index>all(全表扫描)
System:
系统表,少量数据,往往不需要进行磁盘I/O,属于const的特例;const:
常量连接,表示通过索引一次就能找到,通常用于比较primary key 和unique index,由于只匹配一行数据,所以很快。例如我们将主键置于where列表中,MYSQl就能将此查询转换成一个常量。eq_ref:
唯一性索引扫描,对于每一个索引键,表中只有一条记录与之匹配。通常用于主键索引(primary key) 和非空唯一索引(unique not null)等值查询。即PK或者unique索引上的join查询,等值匹配,对于前表的每一行(row),后表只有一行命中ref:
非唯一索引扫描,返回匹配某个单独值的行,本质上也是一种索引访问,它返回所有匹配某个单独值的行。此查询可能找到多个符合条件的行,所以这个应该属于查找和扫描的混合体。range:
范围扫描,只检索给定范围的行,使用一个索引来选择行。在key
列会显示使用了那个索引,一般就是在WHERE语句中出现了between、 in、<、>等范围的查询。这种范围扫描索引比全表扫描要好,因为它只需要开始于索引的某一点,结束于另一点,不用扫描全部索引。index:
索引树扫描,即扫描全部索引(FULL INDEX SCAN), 由于索引文件通常比数据文件小,所以比all快。例如InnoBD的count,all
:全表扫描(FULL TABLE SCAN)
possible_key
显示可能应用在这张表中的索引,一个或者多个。查询所涉及的字段上若存在索引,则该索引将被列出,但是不一定被查询实际使用。
key
实际使用的索引,如果为NULL,则没有使用索引。查询中若是使用了覆盖索引,则该索引仅出现在key列表中, key参数可以作为使用了索引的判断标准
覆盖索引(Covering Index):
包含所有满足查询需要的数据的索引
MySQL可以利用索引返回select列表中的字段,而不必根据索引再次读取数据文件
注意:如果要使用覆盖索引,一定要注意select列表中只取出需要的列,不可select *,
因为如果将所有字段一起做索引会导致索引文件过大,查询性能下降
key_len
表示索引中使用的字节数,可通过该列计算查询中索引的长度,再不损失精确性的情况下,长度越短越好。
key_len显示的值为索引字段的最大可能长度,并非实际使用长度,即key_len是根据表定义计算而得,并非通过表内检索得出
ref
表的连接匹配条件,显示索引的那一列被使用了,如果可能的话,是一个常数。即哪些列或者常量被用于查找索引上的值
rows
MySQL根据表统计信息及索引选用情况,估算的找出所需记录所需要读取的行数
fileterd
表示存储引擎返回的数据在server层过滤后,剩下多少满足查询的记录数量的比例,注意是百分比,不是具体记录数。
Elxtra
-
Using filesort:
危险,需要尽快优化说明MySQL会对数据使用一个外部的索引排序,而不是按照表内的索引顺序进行读取,MySQl中无法利用索引完成的排序操作称为"文件排序" 排序的时候最好遵循所建索引的顺序与个数,否则就可能会出现Using filesort -
Using temporary:`十分危险,极大的影响SQl性能,需要尽快优化 使用临时表保存中间结果,mysql在对查询结果排序时使用临时表。常见于order by 和分组查询group by。group by 一定要遵循所建索引的顺序与个数
-
Using index:
表示相应的select操作中使用了覆盖索引,避免访问表的数据行,效率不错。 如果同事出现Using where
,表明索引被用来执行索引键值的查找; 如果没有同时出现Using where
, 表明索引用来读取数据而非执行查找。 对两个字段建立索引将其中一个字段作为where 条件就符合键值查找。 -
Using where:
表明索引被用来索引键值的查找。即如果我们不是读取表的所有数据,或者不仅仅是通过索引就可以获取所有所需数据时 -
Using join buffer:
使用了连接缓存。即在获取连接条件时没有使用索引,并且需要连接缓冲区来存储中间结果。如果出现此值,那么我们可以根据具体的查询情况添加索引来改进查询 -
index merges:
当MySQL决定要在一个给定的表上使用超过一个索引的时候,就会出现下列格式中的一个,详细说明使用索引以及合并的类型。Using sort union(...)/Using union(...)/Using intersect(..)
-
const row not found :
类似于select … from table_name ,但是表记录为空 -
Deleting all rows:
对于DELETE,一些存储引擎(如MyISAM)支持一种处理方法,可以简单而快速地删除所有的表行。 如果引擎使用此优化,则会显示此额外值 -
Distinct:
MySQL正在寻找不同的值,因此在找到第一个匹配行后,它将停止搜索当前行组合的更多行 -
firstMatch:
半连接去重执行优化策略,当匹配了第一个值之后立即放弃之后记录的搜索。这为表扫描提供了一个早期退出机制而且还消除了不必要记录的产生。半连接 :当一张表在另一张表找到匹配的记录之后,半连接(semi-jion)返回第一张表中的记录。与条件连接相反,即使在右节点中找到几条匹配的记录,左节点的表也只会返回一条记录。另外,右节点的表一条记录也不会返回。半连接通常使用IN或EXISTS 作为连接条件。
-
Start temporary, End temporary
:表示半连接中使用DuplicateWeedout策略的临时表 -
Full scan on NULL key :
子查询中的一种优化方式,主要在遇到无法通过索引访问null值的使用 -
LooseScan(m..n) :
利用索引来扫描一个子查询表可以从每个子查询的值群组中选出一个单一的值。松散扫描(LooseScan)策略采用了分组,子查询中的字段作为一个索引且外部SELECT语句可以可以与很多的内部SELECT记录相匹配。如此便会有通过索引对记录进行分组的效果。 -
Impossible HAVING:
HAVING子句总是为false,不能选择任何行 -
Impossible WHERE:
WHERE子句始终为false,不能选择任何行 -
Impossible WHERE noticed after reading const tables:
MySQL读取了所有的const和system表,并注意到WHERE子句总是为false -
No matching min/max row:
没有满足SELECT MIN(…)FROM … WHERE查询条件的行 -
no matching row in const table:
表为空或者表中根据唯一键查询时没有匹配的行 -
No matching rows after partition pruning:
对于DELETE或UPDATE,优化器在分区修剪后没有发现任何删除或更新。 对于SELECT语句,它与Impossible WHERE的含义相似 -
No tables used:
没有FROM子句或者使用DUAL虚拟表。注意:DUAL虚拟表纯粹是为了方便那些要求所有SELECT语句应该有FROM和可能的其他子句的人。 MySQL可能会忽略这些条款。 如果没有引用表,MySQL不需要FROM DUAL
-
Not exists:
MySQL能够对查询执行LEFT JOIN优化,并且在找到与LEFT JOIN条件匹配的一行后,不会在上一行组合中检查此表中的更多行。 -
Range checked for each record (index map: N) :
MySQL发现没有使用好的索引,但是发现在前面的表的列值已知之后,可能会使用一些索引。 对于上表中的每一行组合,MySQL检查是否可以使用range或index_merge访问方法来检索行。 这不是很快,但比执行没有索引的连接更快。
index map N索引的编号从1开始,按照与表的SHOW INDEX所示相同的顺序。 索引映射值N是指示哪些索引是候选的位掩码值。 例如,0x19(二进制11001)的值意味着将考虑索引1,4和5。 -
Select tables optimized away:
当我们使用某些聚合函数来访问存在索引的某个字段时,优化器会通过索引直接一次定位到所需要的数据行完成整个查询。在使用某些聚合函数如min, max的query,直接访问存储结构(B树或者B+树)的最左侧叶子节点或者最右侧叶子节点即可,这些可以通过index解决。Select count(*) from table(不包含where等子句),MyISAM保存了记录的总数,可以直接返回结果,而Innodb需要全表扫描。Query中不能有group by操作 -
Skip_open_table, Open_frm_only, Open_full_table
这些值表示适用于INFORMATION_SCHEMA表查询的文件打开优化;
Skip_open_table:表文件不需要打开。信息已经通过扫描数据库目录在查询中实现可用。
Open_frm_only:只需要打开表的.frm文件。
Open_full_table:未优化的信息查找。必须打开.frm,.MYD和.MYI文件。 -
unique row not found:
对于诸如SELECT … FROM tbl_name的查询,没有行满足表上的UNIQUE索引或PRIMARY KEY的条件。 -
Using index condition:
Using index condition 会先条件过滤索引,过滤完索引后找到所有符合索引条件的数据行,随后用 WHERE 子句中的其他条件去过滤这些数据行; -
Using join buffer (Block Nested Loop), Using join buffer (Batched Key Access)
*注:
Block Nested-Loop Join算法:将外层循环的行/结果集存入join buffer, 内层循环的每一行与整个buffer中的记录做比较,从而减少内层循环的次数。优化器管理参数optimizer_switch中中的block_nested_loop参数控制着BNL是否被用于优化器。默认条件下是开启,若果设置为off,优化器在选择 join方式的时候会选择NLJ(Nested Loop Join)算法。
Batched Key Access原理:对于多表join语句,当MySQL使用索引访问第二个join表的时候,使用一个join buffer来收集第一个操作对象生成的相关列值。BKA构建好key后,批量传给引擎层做索引查找。key是通过MRR接口提交给引擎的(mrr目的是较为顺序)MRR使得查询更有效率,要使用BKA,必须调整系统参数optimizer_switch的值,batched_key_access设置为on,因为BKA使用了MRR,因此也要打开MRR -
Using MRR
使用MRR策略优化表数据读取,仅仅针对二级索引的范围扫描和 使用二级索引进行 join 的情况;
过程:先根据where条件中的辅助索引获取辅助索引与主键的集合,再将结果集放在buffer(read_rnd_buffer_size 直到buffer满了),然后对结果集按照pk_column排序,得到有序的结果集rest_sort。最后利用已经排序过的结果集,访问表中的数据,此时是顺序IO。即MySQL 将根据辅助索引获取的结果集根据主键进行排序,将无序化为有序,可以用主键顺序访问基表,将随机读转化为顺序读,多页数据记录可一次性读入或根据此次的主键范围分次读入,减少IO操作,提高查询效率。
注:MRR原理:Multi-Range Read Optimization,是优化器将随机 IO 转化为顺序 IO 以降低查询过程中 IO 开销的一种手段,这对IO-bound类型的SQL语句性能带来极大的提升,适用于range ref eq_ref类型的查询;
注意:
EXPLAIN不会告诉你关于触发器、存储过程的信息或用户自定义函数对查询的影响情况
EXPLAIN不考虑各种Cache
EXPLAIN不能显示MySQL在执行查询时所作的优化工作
部分统计信息是估算的,并非精确值
EXPALIN只能解释SELECT操作,其他操作要重写为SELECT后查看执行计划。
关于Extra详细解释和例子可以查看:
关于type类型的举例分析可以查看:MySQL explain,type分析(转)