MySQL Explain机制!

table列:

表示 explain 的一行正在访问哪个表。

当 from 子句中有子查询时,table列是 <derivenN> 格式:

  • 表示当前查询依赖 id=N 的查询,先执行 id=N 的查询。
  • 当有 union 时,UNION RESULT 的 table 列的值为<union1,2>,1和2表示参与 union 的 select 行id。

id列:

id列的编号是 select 的序列号,有几个 select 就有几个id,并且id的顺序是按 select 出现的顺序增长的。

  • id列越大执行优先级越高,id相同则从上往下执行,id为NULL最后执行。

select_type列:

SIMPLE

  • 查询语句中不包含UNION或者子查询的查询都算作是SIMPLE类型。

PRIMARY

  • 对于包含UNION、UNION ALL或者子查询的大查询来说,它是由几个小查询组成。
  • 其中最左边的那个查询的select_type值就是PRIMARY。

type列:

从最优到最差分别为:system > const > eq_ref > ref > range > index > ALL

  • 一般来说,得保证查询达到range级别,最好达到ref。

eq_ref

  • primary keyunique key 索引使用,最多只会返回一条符合条件的记录。

ref:

  • 当通过普通二级索引来查询某个表,那么对该表的访问方法就可能是ref。
  • 相比 eq_ref,不使用唯一索引,可能会找到多个符合条件的行。

ref_or_null

  • 当对普通二级索引查询,该索引列的值可以是NULL值时,那么对该表的访问方法就可能是ref_or_null

range

  • 范围扫描通常出现在 in(), between ,> ,<, >= 等操作中。
  • 使用一个索引来检索给定范围的行。

index:

  • 当使用索引覆盖,但需要扫描全部的索引记录时,该表的访问方法就是index。

index_merge:

  • 一般情况下对于某个表的查询只能使用到一个索引,但在某些场景下可以使用多种索引合并的方式来执行查询。

ALL:

  • 全表扫描。

possible_keys列:

显示查询可能使用哪些索引来查找。

key_len列:

显示了索引里使用的字节数,通过这个值可以算出具体使用了索引中的哪些列。

key_len计算规则如下:

字符串:

  • char(n):n字节,varchar(n):2字节,如果是utf-8,则长度 3n + 2

数值类型:

  • tinyint:1字节,smallint:2字节,int:4字节,bigint:8字节

 

时间类型:

  • date:3字节,timestamp:4字节,datetime:8字节

rows列:

读取并检测的行数,注意这个不是结果集里的行数。

  • 如果使用全表扫描查询时,执行计划的rows列就代表预计需要扫描的行数。

  • 如果使用索引查询时,执行计划的rows列就代表预计扫描的索引记录行数。

ref列:

显示了在key列记录的索引中,表查找值所用到的列或常量,常见的有:const(常量),字段名。

  • ref列展示的就是与索引列作等值匹配的值什么,比如只是一个常数或者是某个列。

Extra列:

Using index

  • 查询的列被索引覆盖,并且where筛选条件是索引的前导列。
  • 一般是使用了覆盖索引(索引包含了所有查询的字段)。

Using where

  • 使用全表扫描来执行对某个表的查询,并且该语句的WHERE子句中有针对该表的搜索条件时。

Using where Using index

  • 查询的列被索引覆盖,并且where筛选条件是索引列之一但是不是索引的前导列。
    • 意味着无法直接通过索引查找来查询到符合条件的数据。

Using index condition

  • 查询的列不完全被索引覆盖,where条件中是一个前导列的范围。

Using temporary

  • 在执行DISTINCT、GROUP BY、UNION等子句的查询时。
  • 如果不能利用索引来完成查询,MySQL通过建立内部的临时表来执行查询。

Using filesort

  • 会对结果使用一个外部索引排序,而不是按索引次序从表里读取行。

MySQL EXPLAIN 扫描行数准确吗?

EXPLAIN 的结果会包含 rows 列,它表示SQL 预计扫描的行数,但这只是估算值

如果想获取实际扫描的行数,需要使用 EXPLAIN ANALYZE

1
EXPLAIN ANALYZE SELECT * FROM your_table WHERE some_column = 'value';

在 MySQL 8.0 及以上版本,这个命令会真正执行查询,并提供实际扫描的行数

通常在 analyze 输出的 rows_examined 字段中可以看到。