MySql执行计划

xiaoxiao2021-03-01  25

mysql执行计划

1. mysql执行路径


mysql执行路径 客户端发送一条查询给服务器;服务器先会检查查询缓存,如果命中了缓存,则立即返回存储在缓存中的结果。否则进入下一阶段;服务器端进行SQL解析、预处理,再由优化器生成对应的执行计划;MySQL根据优化器生成的执行计划,调用存储引擎的API来执行查询;将结果返回给客户端。 mysql缓存配置

show variables like ‘%query_cache%’

注意:后期有兴趣可以深入了解mysql的缓存,目前仅仅是简单的了解一下。

参数名称解释have_query_cache标识数据库是否支持query_cachequery_cache_limitMySQL能过缓存的最大结果。若查询结果大于这个值,则不会被缓存。query_cache_min_res_unit在查询缓存中分配内存时的最小单位query_cache_size查询缓存使用的总内存空间,单位字节。query_cache_type是否打开查询缓存。可以设置为OFF,ON,DEMANDquery_cache_wlock_invalidate如果某个数据表被锁住,是否仍然从缓存中返回数据,默认是OFF,表示仍然可以返回

参考文档 :https://www.cnblogs.com/Alight/p/3981999.html

2.执行计划


数据库执行SQL语句是按照一定顺序,分步骤完成的。这些用来执行目标SQL语句的步骤的组合就被称为执行计划。至于采用怎样的顺序,用什么方法访问数据,是由优化器来决定的。

sql执行顺序

sql执行计划

使用explain关键字可以模拟优化器执行SQL查询语句,从而知道MySQL是如何处理你的SQL语句的。

explain SELECT * FROM im_group_user WHERE user_id=1

ColumnJSON NameMeaningidselect_id选择标识符select_typeNone选择类型tabletable_name输出行的表(表名)partitionspartitions匹配分区typeaccess_type连接类型possible_keyspossible_keys选择的可能指标(列预估了mysql能够为当前查询选择的索引,个字段是完全独立于执行计划中输出的表的顺序,意味着在实际查询中可能用不到这些索引。 )keykey实际选择的指标(如果mysql优化过程中没有加索引,可以强制加hint使用索引)key_lenkey_length所选密钥的长度(表示了mysql使用的索引的长度)refref与索引比较的列(连接匹配条件,如果走主键索引的话,该值为: const, 全表扫描的话,为null值,主键的为主键名称)rowsrows预估待检查行(扫描行数,通常情况下,rows越小,效率越高,也就有大部分SQL优化,都是在减少这个值的大小)filteredfiltered表条件过滤的行百分比ExtraNone此列包含有关MySQL如何解析查询的附加信息

id

选择标识符。这是查询中SELECT的序号(主要是用来标识sql执行顺序)。如果行引用其他行的联合结果,则值可以为NULL。在这种情况下,表列显示一个值,如 < unionM,N >,以指示行引用具有m和n的ID值的行的联合。

select_type

该表示选择的类型

select_typeJSON NameMeaningSIMPLENone简单选择(不使用联合或子查询)PRIMARYNone最外选择(查询中包含任何复杂的子部分,最外层查询则被标记为primary)UNIONNoneUNION中的第二或更晚SELECT语句(若第二个select出现在union之后,则被标记为union;若union包含在from子句的子查询中,外层select将被标记为derived)DEPENDENT UNIONdependent (true)UNION中的第二或更晚SELECT语句,依赖于外部查询UNION RESULTunion_resultUNION的结果SUBQUERYNone子查询中的第一选择(在select 或 where列表中包含了子查询 )DEPENDENT SUBQUERYdependent (true)首先在子查询中选择,依赖于外部查询DERIVEDNone衍生的表(在from列表中包含的子查询被标记为derived(衍生),mysql或递归执行这些子查询,把结果放在零时表里 )MATERIALIZEDmaterialized_from_subquery物化子查询UNCACHEABLE SUBQUERYcacheable (false)无法缓存结果的子查询,必须对外部查询的每行重新进行评估(表示子查询不可被物化 需要逐次运行)。UNCACHEABLE UNIONcacheable (false)在属于不可撤销子查询的UNION中的第二次或以后的选择(同上,子查询中出现union 并且不可被缓存 在union 后的select 语句出现此关键词)

table

输出行引用的表的名称。这也可以是下列值之一: < unionM,N>:行是指行与m和n的ID值的结合。 < derivedN >:指的是具有ID值n的行的派生表结果。派生表可能是从FROM子句中的子查询生成的 < subqueryN >:指的是具有ID值N的行的物化子查询的结果

partitions

将由查询匹配记录的分区。未分区表的值为NULL。

type

连接类型 NULL->system->const->eq-ref->ref->fulltext->ref_or_null->index_merge->unique_subquery->index_subquery->range->index->ALL

nameMeaningsystem该表只有一行(=系统表)。这是const连接类型的特殊情况。const该表最多有一个匹配行,它在查询开始时被读取。因为只有一行,所以该行中的列的值可以被优化器的其余部分视为常量。const表非常快,因为它们只读一次。eq-ref每次与之前的表合并行都只在该表读取一行,这是除了system,const之外最好的一种,特点是使用=,而且索引的所有部分都参与join且索引是主键或非空唯一键的索引ref如果每次只匹配少数行,那就是比较好的一种,使用=或<=>,可以是左覆盖索引或非主键或非唯一键fulltext全文搜索ref_or_null此连接类型类似于REF,但是MySQL对包含空值的行进行了额外的搜索。这种连接类型优化最常用于解析子查询index_merge表示出现了索引合并优化(包括交集,并集以及交集之间的并集),但不包括跨表和全文索引。 这个比较复杂,目前的理解是合并单表的范围索引扫描(如果成本估算比普通的range要更优的话)unique_subquery在in子查询中,就是value in (select…)把形如“select unique_key_column”的子查询替换。PS:所以不一定in子句中使用子查询就是低效的!index_subquery同上,但把形如”select non_unique_key_column“的子查询替换range只有在给定范围内的行才被检索,使用索引来选择行。输出行中的键列指示使用哪个索引。key_len 包含使用的最长的关键部分。此类型的REF列为NULL(与一个常数比较时,可以使用任何一个 =, <>, >, >=, <, <=, IS NULL, <=>, BETWEEN, LIKE, or IN())indexa.当查询是索引覆盖的,即所有数据均可从索引树获取的时候(Extra中有UsingIndex);b.以索引顺序从索引中查找数据行的全表扫描(无 UsingIndex); c.如果Extra中Using Index与Using Where同时出现的话,则是利用索引查找键值的意思; d.如单独出现,则是用读索引来代替读行,但不用于查找ALL遍历全表以找到匹配的行

注意 type = NULL,MYSQL不用访问表或者索引就直接能到结果。

possible_keys

查询涉及到的字段上存在索引,则该索引将被列出,但不一定被查询实际使用,如果此列为NULL(或JSON格式输出中未定义),则不存在相关索引。在这种情况下,您可以通过检查WHERE子句来检查查询是否是指适合于索引的某些列或列,从而提高查询的性能

key

实际使用的索引,如果为NULL,则没有使用索引。 查询中如果使用了覆盖索引,则该索引仅出现在key列表中

key_len

表示索引中使用的字节数,查询中使用的索引的长度(最大可能长度),并非实际使用长度,理论上长度越短越好。key_len是根据表定义计算而得的,不是通过表内检索出的(如果键列表示NULL,key_len列也表示NULL。)

ref

非唯一性索引扫描,返回匹配某个单独值的所有行。本质是也是一种索引访问,它返回所有匹配某个单独值的行,然而他可能会找到多个符合条件的行,所以它应该属于查找和扫描的混合体

rows

行列指示MySQL认为必须执行的行执行查询的行数。对于InnoDB表,这个数字是一个估计值,

filtered

过滤列表示由表条件过滤的表行的估计百分比。最大值为100,这意味着没有发生行过滤。值从100下降表明过滤量增加。行显示估计的行数检查,行×筛选显示将与下表连接的行数。例如,如果行为1000并且过滤为50(50%),则与下表结合的行数为1000×50%=500。

Extra

此列包含有关MySQL如何解析查询的附加信息

nameMeaningconst row not found对于查询,如SELECT … FROM tbl_name中,表是空的。Deleting all rows对于删除,一些存储引擎(如MyISAM)支持以简单快捷的方式移除所有表行的处理程序方法。如果引擎使用此优化,则显示此额外值。DistinctMySQL正在寻找不同的值,因此在找到第一个匹配行之后,它不再为当前行组合搜索更多行FirstMatch(tbl_name)半连接去重执行优化策略,当匹配了第一个值之后立即放弃之后记录的搜索。这为表扫描提供了一个早期退出机制而且还消除了不必要记录的产生Full scan on NULL key当优化器无法使用索引查找访问方法时,这会发生子查询优化作为回退策略(子查询中的一种优化方式,主要在遇到无法通过索引访问null值的使用)Impossible HAVINGHAVING子句总是false,不能选择任何行Impossible WHEREWHERE子句总是FALSE,不能选择任何行。Impossible WHERE noticed after reading const tablesMySQL已经读取了所有const(和system)表,并注意到WHERE子句总是FALSE。LooseScan(m..n)利用索引来扫描一个子查询表可以从每个子查询的值群组中选出一个单一的值。松散扫描(LooseScan)策略采用了分组,子查询中的字段作为一个索引且外部SELECT语句可以可以与很多的内部SELECT记录相匹配。如此便会有通过索引对记录进行分组的效果no matching row in const table没有行满足查询的条件,例如 SELECT MIN(…) FROM … WHERE condition.No matching min/max rowconst表中没有匹配行No matching rows after partition pruning对于DELETE或UPDATE,优化器在分区修剪后没有发现任何删除或更新。 对于SELECT语句,它与Impossible WHERE的含义相似No tables used查询没有从句,或者有一个从句。Not existsMySQL能够对查询执行LEFT JOIN优化,并且在找到与LEFT JOIN条件匹配的一行后,不会在上一行组合中检查此表中的更多行Plan isn’t ready yet当优化器尚未完成在命名连接中执行的语句的执行计划时,其值发生在连接的说明中。如果执行计划输出包含多个行,则它们中的任何一个或全部都可以具有此额外值,这取决于优化器在确定完整执行计划时的进度。Range checked for each recordMySQL发现没有使用好的索引,但是发现在前面的表的列值已知之后,可能会使用一些索引。 对于上表中的每一行组合,MySQL检查是否可以使用range或index_merge访问方法来检索行。 这不是很快,但比执行没有索引的连接更快Recursive这表示该行应用于递归公共表表达式的递归选择部分Scanned N databases这指示了在处理查询信息模式表时服务器执行多少目录扫描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文件。Start temporary, End temporary这表示临时表用于半连接重复删除策略unique row not found对于查询,如SELECT … FROM tbl_name,没有行满足表上唯一索引或主键的条件。Using filesort当Query 中包含 ORDER BY 操作,而且无法利用索引完成排序操作的时候,MySQL Query Optimizer 不得不选择相应的排序算法来实现。数据较少时从内存排序,否则从磁盘排序。Explain不会显示的告诉客户端用哪种排序。官方解释:“MySQL需要额外的一次传递,以找出如何按排序顺序检索行。通过根据联接类型浏览所有行并为所有匹配WHERE子句的行保存排序关键字和行的指针来完成排序。然后关键字被排序,并按排序顺序检索行”Using index仅使用索引树中的信息从表中检索列信息,而不需要进行附加搜索来读取实际行(使用二级覆盖索引即可获取数据)。 当查询仅使用作为单个索引的一部分的列时,可以使用此策略 示例中第一个查询所有数据时,无法通过emp_number的覆盖索引来获取整行数据,所以需要根据主键id回表查询表数据Using index condition会先条件过滤索引,过滤完索引后找到所有符合索引条件的数据行,随后用 WHERE 子句中的其他条件去过滤这些数据行Using index for group-by数据访问和 Using index 一样,所需数据只须要读取索引,当Query 中使用GROUP BY或DISTINCT 子句时,如果分组字段也在索引中,Extra中的信息就会是 Using index for group-by。注:和Using index一样,只需读取覆盖索引Using index for skip scan指示使用跳过扫描访问方法。见跳过扫描范围访问方法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,因此也要打开MRRUsing MRR使用多范围读取优化策略读取表Using sort_union(…), Using union(…), Using intersect(…)这些指示索引扫描如何合并为index_merge连接类型。Using temporary要解决查询,MySQL需要创建一个临时表来保存结果Using where表示Mysql将对storage engine提取的结果进行过滤,过滤条件字段无索引Using where with pushed condition此项仅适用于NDB表。这意味着MySQL集群正在使用条件下推优化来提高非索引列和常数之间的直接比较的效率Zero limit查询有一个限制0子句,不能选择任何行。

3. sql优化策略


优化器分类

RBO: Rule-Based Optimization 基于规则的优化器 CBO: Cost-Based Optimization 基于代价的优化器

优化原则


参考文档 :

https://dev.mysql.com/doc/refman/5.7/en/explain-output.html

https://blog.csdn.net/wuseyukui/article/details/71512793

https://blog.csdn.net/daohengshangqian/article/details/50561477

转载请注明原文地址: https://www.6miu.com/read-4050333.html

最新回复(0)