如何看懂执行计划
在MySQL中,执行计划(也称为Explain计划)是一个工具,它用于解释MySQL执行特定查询时的数据检索方法。执行计划可以展示MySQL是如何使用索引,是如何进行表连接,以及使用了哪些优化方法。这对于查询性能调优非常重要,因为它可以帮助发现性能瓶颈并优化查询。
以下是如何获取MySQL查询的执行计划的基本步骤:
执行带有EXPLAIN
关键字的查询。你只需将EXPLAIN
放在要分析的查询语句前面即可。例如:
EXPLAIN SELECT * FROM your_table WHERE your_column = 'some_value';
id:select子句或表执行顺序,id相同,从上到下执行,id不同,id值越大,执行优先级越高。
select_type:查询的类型
- SIMPLE:简单的select查询,查询中不包含子查询或union查询。
- PRIMARY:查询中若包含任何复杂的子部分,最外层查询为PRIMARY,也就是最后加载的就是PRIMARY。
- SUBQUERY:在select或where列表中包含了子查询,就为被标记为SUBQUERY。
- DERIVED:在from列表中包含的子查询会被标记为DERIVED(衍生),MySQL会递归执行这些子查询,将结果放在临时表中。
- UNION:若第二个select出现在union后,则被标记为UNION,若union包含在from子句的子查询中,外层select将被标记为DERIVED。
- UNION RESULT:从union表获取结果的select。
table:显示sql操作属于哪张表的。
partitions:匹配的分区,值为NULL表示表未被分区。
type:对表访问方式,表示MySQL在表中找到所需行的方式,又称"访问类型"。
- ALL:Full Table Scan, MySQL将遍历全表以找到匹配的行
- index:Full Index Scan,index与ALL区别为index类型只遍历索引树
- range:只检索给定范围的行,使用一个索引来选择行
- ref_or_null:这种连接类型类似于ref,但是MySQL会额外搜索包含NULL值的行。此联接类型优化最常用于解析子查询
- fulltext:使用fulltext索引执行连接。
- ref:表示上述表的连接匹配条件,即哪些列或常量被用于查找索引列上的值
- eq_ref:类似ref,区别就在使用的索引是唯一索引,对于每个索引键值,表中只有一条记录匹配,就是多表连接中使用primary key或者 unique key作为关联条件
- const:当MySQL对查询某部分进行优化,并转换为一个常量时,使用这些类型访问。如将主键置于where列表中,MySQL就能将该查询转换为一个常量,
- system:system是const类型的特例,当查询的表只有一行的情况下。
possible_keys:显示可能应用在表中的索引,可能一个或多个。查询涉及到的字段若存在索引,则该索引将被列出,但不一定被查询实际使用。
Key:key列显示MySQL实际决定使用的键(索引),必然包含在possible_keys中,如果没有选择索引,键是NULL。要想强制MySQL使用或忽视possible_keys列中的索引,在查询中使用FORCE INDEX、USE INDEX或者IGNORE INDEX。
key_len:表示索引中使用的字节数,可通过该列计算查询中使用的索引的长度(key_len显示的值为索引字段的最大可能长度,并非实际使用长度,即key_len是根据表定义计算而得,不是通过表内检索出的)
ref:关联的字段,常量等值查询,显示为const,如果为连接查询,显示关联的字段。
rows:MySQL估计为了执行查询而必须检查的行数
Extra:显示十分重要的额外信息。
- Using filesort:表明mysql会对数据使用一个外部的索引排序,而不是按照表内的索引顺序进行读取。mysql中无法利用索引完成的排序操作称为"文件排序"。出现Using filesort就非常危险了,在数据量非常大的时候几乎"九死一生"。出现Using filesort尽快优化sql语句。
- Using temporary:使用了临时表保存中间结果,常见于排序order by和分组查询group by。非常危险,"十死无生",急需优化。
- Using index:表明相应的select操作中使用了覆盖索引,避免访问表的额外数据行,效率不错。
根据执行计划来优化查询性能
-
添加或调整索引:
EXPLAIN
命令返回的结果中的key
列显示了MySQL在查询中实际使用的索引,possible_keys
列显示了本次查询可能使用的全部索引。您可以根据这两列了解索引的使用情况。如果发现查询没有使用索引(type
列显示为ALL
或index
),或者使用了全字段的索引(key_len
列的长度很长),那么可能需要添加新的索引或者调整现有的索引。 -
修改查询结构:对查询进行部分修改,比如改变连接顺序,使用或不使用子查询,可以改善查询性能。例如,「IN (子查询)」这样的查询结构通常可以被改写为JOIN查询,以获得更好的性能。
-
调整查询条件:查询的
WHERE
条件可能会影响到索引的使用,过于复杂的查询条件或者对列进行函数处理(比如WHERE DATE(datetime) = '2022-01-01'
)可能会导致索引失效。调整WHERE
条件,使其尽可能利用索引,可以提高查询性能。 -
优化数据方式:比如对于字符串类型,选择合适的字符集和整理顺序(Collation)有助于提高查询效率。同时,也可以通过改变存储引擎改善查询和写入性能。
-
使用分区:对大表进行分区,可以根据查询条件只读取部分分区的数据,从而提高查询性能。