当前位置:   article > 正文

explain分析sql_mysql explain 只有 query plan

mysql explain 只有 query plan
  • 性能分析explain
    MySql Query Optimizer是MySql中专门负责优化select语句的优化器模块,主要功能:通过计算分析系统中收集到的系统信息,为客户端请求的Query提供他认为最优的执行计划(系统认为最优的数据检索方式,但不见得是DBA认为最优的,这部分最耗费时间)

  • MySQL常见瓶颈
    CPU: CPU在饱和的时候一般发生在数据装入内存或从磁盘上读取数据时候
    IO: 磁盘I/O瓶颈发生在装入数据远大于内存容量的时候
    服务器硬件的性能瓶颈:top,free, iostat和vmstat来查看系统的性能状态。

  • 能干哈
    表的读取顺序(对应explain的id)
    数据读取操作的操作类型
    哪些索引可以使用
    哪些索引被实际使用
    表之间的引用
    每张表有多少行被优化器查询

在这里插入图片描述


在这里插入图片描述

id选择标识符

id列数字越大越先执行;
如果说数字一样大,那么就从上往下依次执行;
id列为null的就表示这是一个结果集,不需要使用它来进行查询。

select_type查询的类型

  • simple:表示不需要union操作或者不包含子查询的简单select查询。有连接查询时,外层的查询为simple,且只有一个
  • primary:子查询中最外层查询,查询中若包含任何复杂的子部分,需要union操作或者含有子查询的select,位于最外层的单位查询的select_type即为primary。且只有一个
  • derived:from字句中出现的子查询,也叫做衍生表,其他数据库中可能叫做内联视图或嵌套select
  • subquery:除了from字句中包含的子查询外,其他地方出现的子查询都可能是subquery
  • union:union连接的两个select查询,第一个查询是dervied派生表,除了第一个表外,第二个以后的表select_type都是union
  • union result:union的结果集,在union和union all语句中,因为它不需要参与查询,所以id字段为null
  • dependent union:与union一样,出现在union 或union all语句中,但是这个查询要受到外部查询的影响
  • dependent subquery:与dependent union类似,表示这个subquery的查询要受到外部表查询的影响

在这里插入图片描述

table显示的查询表名

如果查询使用了别名,那么这里显示的是别名;
如果不涉及对数据表的操作,那么这显示为null;
如果显示为尖括号括起来的就表示这个是临时表,后边的N就是执行计划中的id,表示结果来自于这个查询产生;
如果是尖括号括起来的<union M,N>,与类似,也是一个临时表,表示这个结果来自于union查询的id为M,N的结果集

type表的连接类型

依次从好到差:system,const,eq_ref,ref,fulltext,ref_or_null,unique_subquery,index_subquery,range,index_merge,index,ALL,除了all之外,其他的type都可以使用到索引,除了index_merge之外,其他的type只可以用到一个索引
常用的 system>const>eq_ref>ref>range>index>ALL : 一般来说,得保证查询至少达到range级别,最好能达到ref。

  • system:表中只有一行数据或者是空表,且只能用于myisam和memory表。如果是Innodb引擎表,type列在这个情况通常都是all或者index
  • const:使用唯一索引或者主键,返回记录一定是1行记录的等值where条件时,通常type是const。其他数据库也叫做唯一索引扫描
  • eq_ref:出现在要连接多个表的查询计划中,驱动表只返回一行数据,且这行数据是第二个表的主键或者唯一索引,且必须为not null,唯一索引和主键是多列时,只有所有的列都用作比较时才会出现eq_ref
    类似ref,区别就在使用的索引是唯一索引,对于每个索引键值,表中只有一条记录匹配,简单来说,就是多表连接中使用primary key或者 unique key作为关联条件
  • ref:不像eq_ref那样要求连接顺序,也没有主键和唯一索引的要求,只要使用相等条件检索时就可能出现,常见与辅助索引的等值查找。或者多列主键、唯一索引中,使用第一个列之外的列作为等值查找也会出现,总之,返回数据不唯一的等值查找就可能出现。
  • fulltext:全文索引检索,要注意,全文索引的优先级很高,若全文索引和普通索引同时存在时,mysql不管代价,优先选择使用全文索引
  • ref_or_null:与ref方法类似,只是增加了null值的比较。实际用的不多。
  • unique_subquery:用于where中的in形式子查询,子查询返回不重复值或唯一值
  • index_subquery:用于in形式子查询使用到了辅助索引或者in常数列表,子查询可能返回重复值,可以使用索引将子查询去重。
  • range:索引范围扫描,常见于使用 !=, <>, >, >=, <, <=, IS NULL, <=>, BETWEEN, LIKE, or IN() 等运算符的查询中。
  • index_merge:表示查询使用了两个以上的索引,最后取交集或者并集,常见and ,or的条件使用了不同的索引,官方排序这个在ref_or_null之后,但是实际上由于要读取所有索引,性能可能大部分时间都不如range
  • index:即:Full Index Scan(全索引扫描)。当查询只使用属于单个索引的列时,MySQL可以使用这种连接类型。这种类型和ALL是差不多的,ALL是扫描全表,index是扫描全索引。index会发生在以下两种情况:1. 使用到了覆盖索引 2. 按照索引的顺序来进行读取数据
  • all:这个就是全表扫描数据文件,然后再在server层进行过滤返回符合要求的记录。全表扫描,最差的一种查询。不带where条件或者where条件没有使用到任何索引的情况。
  • null:不需要用到表就可以返回结果

possible_keys 查询可能使用到的索引都会在这里列出来

key 查询真正使用到的索引

select_type为index_merge时,这里可能出现两个以上的索引,其他的select_type这里只会出现一个。

key_len 用于处理查询的索引长度.

如果是单列索引,那就整个索引长度算进去。
如果是多列索引,那么查询不一定都能使用到所有的列,具体使用到了多少个列的索引,这里就会计算进去,没有使用到的列,这里不会计算进去。留意下这个列的值,算一下你的多列索引总长度就知道有没有使用到所有的列了。要注意,mysql的ICP特性使用到的索引不会计入其中。另外,key_len只计算where条件用到的索引长度,而排序和分组就算用到了索引,也不会计算到key_len中

ref

如果是使用的常数等值查询,这里会显示const。
如果是连接查询,被驱动表的执行计划这里会显示驱动表的关联字段。
如果是条件使用了表达式或者函数,或者条件列发生了内部隐式转换,这里可能显示为func

rows

这里是执行计划中估算的扫描行数,不是精确值

filtered

使用explain extended时会出现这个列,5.7之后的版本默认就有这个字段,不需要使用explain extended了。
这个字段表示存储引擎返回的数据在server层过滤后,剩下多少满足查询的记录数量的比例,注意是百分比,不是具体记录数。

extra

  • Using index:查询时不需要回表查询,直接通过索引就可以获取查询的数据。
  • Using index for group-by:数据访问和 Using index 一样,所需数据只须要读取索引,当Query 中使用GROUP BY或DISTINCT 子句时,如果分组字段也在索引中,Extra中的信息就会是 Using index for group-by。注:和Using index一样,只需读取覆盖索引
  • Using index condition:表示用到了索引下推(需要确保开启了索引下推)。在5.6版本后加入的新特性(Index Condition Pushdown)会先条件过滤索引,过滤完索引后找到所有符合索引条件的数据行,随后用 WHERE 子句中的其他条件去过滤这些数据行
  • Using where:不用读取表中所有信息,仅通过索引就可以获取所需数据,这发生在对表的全部的请求列都是同一个索引的部分的时候,表示mysql服务器将在存储引擎检索行后再进行过滤
  • Using where with pushed condition:仅用在ndb上。Mysql Cluster用Condition Pushdown优化改善非索引字段和常量之间的直接比较。condition被pushed down到cluster的数据节点,并在所有数据节点同时估算,把不合条件的列剔除避免网络传输
  • Using temporary:表示MySQL需要使用临时表来存储结果集,常见于排序和分组查询, group by ; order by 通常会发生这种情况(这种需要尽可能优化)。要解决查询,MySQL需要创建一个临时表来保存结果。 如果查询包含不同列的GROUP BY和ORDER BY子句,则通常会发生这种情况。官方解释:”为了解决查询,MySQL需要创建一个临时表来容纳结果。典型情况如查询包含可以按不同情况列出列的GROUP BY和ORDER BY子句时。很明显就是通过where条件一次性检索出来的结果集太大了,内存放不下了,只能通过家里临时表来辅助处理
  • Using filesort:当Query中包含 order by 操作,而且无法利用索引完成的排序操作称为“文件排序”, MySQL会进行一个额外的遍历来排序,也就是说这种情况的排序字段没有用到索引(这种需要尽可能优化)
  • Using join buffer:该值强调了在获取连接条件时没有使用索引,并且需要连接缓冲区来存储中间结果。如果出现了这个值,那应该注意,根据查询的具体情况可能需要添加索引来改进能。
    *注: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:表示用到了Multi-Range Read优化(需要确保开启了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类型的查询
  • Unique row not found:对于诸如SELECT … FROM tbl_name的查询,没有行满足表上的UNIQUE索引或PRIMARY KEY的条件。
  • Using sort_union(…), Using union(…), Using intersect(…):这些指示索引扫描如何合并为index_merge连接类型。

索引合并交叉口访问算法(The Index Merge Intersection Access Algorithm):
index intersect merge就是多个索引条件扫描得到的结果进行交集运算。显然在多个索引提交之间是 AND 运算时,才会出现 index intersect merge. 下面两种where条件或者它们的组合时会进行 index intersect merge:

  1. 条件使用到复合索引中的所有字段或者左前缀字段;
  2. 主键上的任何范围条件。

intersect merge运行方式:多个索引同时扫描,然后结果取交集。如果所有条件字段都是索引字段,使用索引覆盖扫描,无需回表
示例:

SELECT * FROM innodb_table WHERE primary_key < 10 AND key_col1 = 20;
SELECT * FROM tbl_name WHERE key1_part1 = 1 AND key1_part2 = 2 AND key2 = 2;

索引合并联合访问算法(The Index Merge Union Access Algorithm):
index uion merge就是多个索引条件扫描,对得到的结果进行并集运算,显然是多个条件之间进行的是 OR 运算。以下几种可能会使用到index merge union: 1) 条件使用到复合索引中的所有字段或者左前缀字段(对单字段索引也适用);2) 主键上的任何范围条件;3) 任何符合 index intersect merge 的where条件;
示例:

SELECT * FROM t1 WHERE key1 = 1 OR key2 = 2 OR key3 = 3;
SELECT * FROM innodb_table WHERE (key1 = 1 AND key2 = 2) OR (key3 = ‘foo’ AND key4 = ‘bar’) AND key5 = 5;

索引合并排序联合访问算法(The Index Merge Sort-Union Access Algorithm):
多个条件扫描进行 OR 运算,但是不符合 index union merge算法的,此时可能会使用 sort_union算法,当WHERE子句转换为由组合的多个范围条件 时,此访问算法适用 OR,但索引合并并集算法不适用。
示例:

SELECT * FROM tbl_name WHERE key_col1 < 10 OR key_col2 < 20;
SELECT * FROM tbl_name WHERE (key_col1 > 10 OR key_col2 = 20) AND nonkey_col = 30;

  • Select tables optimized away:这个在MySQL的手册里面没有任何提及,不过看其他各列的数据大概能猜到意思:SELECT操作已经优化到不能再优化了(MySQL根本没有遍历表或索引就返回数据了)。当我们使用某些聚合函数来访问存在索引的某个字段时,优化器会通过索引直接一次定位到所需要的数据行完成整个查询。在使用某些聚合函数如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文件
  • Start temporary, End temporary:duplicate weedout是另一种优化子查询的方法,使用时extra会显示materialize、scan语句。使用duplicate weedout优化时,会先访问in(subquery)查询中的子查询,然后将与外部查询数据表连接后的结果存储到临时表,最后再删除重复记录。dulicate weedout优化过程与连接in(subquery)查询并用group by删除重复记录的过程一样。
  • distinct:在select部分使用了distinc关键字,MySQL正在寻找不同的值,因此在找到第一个匹配行后,它将停止搜索当前行组合的更多行
  • const row not found:类似于select …. from tbl_name,而表记录为空
  • Deleting all rows:对于DELETE,一些存储引擎(如MyISAM)支持一种处理方法,可以简单而快速地删除所有的表行。 如果引擎使用此优化,则会显示此额外值)
  • FirstMatch:半连接去重执行优化策略,当匹配了第一个值之后立即放弃之后记录的搜索。这为表扫描提供了一个早期退出机制而且还消除了不必要记录的产生。半连接: 当一张表在另一张表找到匹配的记录之后,半连接(semi-jion)返回第一张表中的记录。与条件连接相反,即使在右节点中找到几条匹配的记录,左节点的表也只会返回一条记录。另外,右节点的表一条记录也不会返回。半连接通常使用IN或EXISTS 作为连接条件。FirstMatch策略背后的思想和in->exists转换思想相同。然而,FirstMatch有以下的优点:
    1.等价传播可以跨越semi-join边界,但是不能跨越子查询边界。因此,使用FirstMatch将子查询转换成semi-join可以提供一个更好的执行计划
    2.只有一种方式使用in->exists策略,mysql会无条件地使用。对于FirstMatch策略,优化器可以选择是否应该在子查询中使用的所有表都位于join前缀时运行FirstMatch策略,或者在稍后的某个时间点运行FirstMatch策略
    FirstMatch策略意味着子查询的表必须在父查询中的表之后被引用;
    FirstMatch支持相关子查询;
    不能应用于子查询带有group by或聚合函数的场景;
    是否开启FirstMatch是由系统变量optimizer_switch中的firstmatch=on|off设置的。
  • Full scan on NULL key:子查询中的一种优化方式,主要在遇到无法通过索引访问null值的使用
  • LooseScan(m…n):利用索引来扫描一个子查询表可以从每个子查询的值群组中选出一个单一的值。松散扫描(LooseScan)策略采用了分组,子查询中的字段作为一个索引且外部SELECT语句可以可以与很多的内部SELECT记录相匹配。如此便会有通过索引对记录进行分组的效果。
  • Impossible HAVING:HAVING子句总是为false,不能选择任何行
  • Impossible where:表中不存在“a = 2”的记录, 执行“EXPLAIN select * from t where a = 2”时输出“Impossible WHERE noticed after reading const tables”。这个Impossible WHERE noticed after reading const tables的结论并不是通过统计信息做出的,而是真的去实际访问了一遍数据后,发现确实没有“a = 2”的行才得出的。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 或不含任何from子句,注意: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
声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/不正经/article/detail/409830
推荐阅读
相关标签
  

闽ICP备14008679号