MYSQL系列(33):explain命令解析

环境:
mysql> select version();
+-----------+
| version() |
+-----------+
| 8.0.13    |
+-----------+


官方文档

explai可以查看查询优化器如何决定执行查询的主要方法

1、调用explain

mysql> explain select 1\G    -- desc select 1\G
*************************** 1. row ***************************  -- 在查询中每个表的输入中只有一行,如果查询的时两个表的联结,那么输出将有2行
           id: 1
  select_type: SIMPLE    --- 不包含UNION查询和子查询
        table: NULL
   partitions: NULL
         type: NULL
possible_keys: NULL
          key: NULL
      key_len: NULL
          ref: NULL
         rows: NULL
     filtered: NULL
        Extra: No tables used
1 row in set, 1 warning (0.00 sec)

mysql> show warnings\G
*************************** 1. row ***************************
  Level: Note
   Code: 1003
Message: /* select#1 */ select 1 AS `1`  --->实际执行的语句:【已经被查询优化器优化了的语句】

mysql> explain format=json select 1\G
*************************** 1. row ***************************
EXPLAIN: {
  "query_block": {
    "select_id": 1,
    "message": "No tables used"
  }
}

2、explain输出

此例中用到的数据库请参考:https://blog.csdn.net/zhizhengguan/article/details/84373555 安装

含义
id 执行计划的id标志
select_type SELECT的类型
table 输出记录的表
partitions 符合的分区,[PARTITIONS]
type JOIN的类型
possible_keys 优化器可能使用到的索引
key 优化器实际选择的索引
key_len 使用索引的字节长度
ref 进行比较的索引列
rows 优化器预估的记录数量
filtered 根据条件过滤得到的记录的百分比[EXTENDED]
extra 额外的显示选项

id

如果语句当中简单子查询、在FROM中的子查询以及UNION查询,内层的select子句将会按照从外到里顺序编号,对应于在子查询中的位置。否则,id = 1。

  • 简单子查询
ysql> EXplain select (select 1 from sakila.actor limit 1) from sakila.film\G
*************************** 1. row ***************************   
           id: 1             --- select xx from sakila.film 是外层子查询,所以id = 1 
  select_type: PRIMARY
        table: film           ---》从表1,  film中查询
   partitions: NULL
         type: index
possible_keys: NULL
          key: idx_fk_language_id
      key_len: 1
          ref: NULL
         rows: 1000
     filtered: 100.00
        Extra: Using index
*************************** 2. row ***************************  -- 因为这个语句中关联到了2个表,所以有两行
           id: 2          -->select 1 from sakila.actor limit 1是内层子查询,所以id=2。内层子查询先执行。
  select_type: SUBQUERY  
        table: actor       ---》从表2,  actor中查询
   partitions: NULL
         type: index
possible_keys: NULL
          key: idx_actor_last_name
      key_len: 137
          ref: NULL
         rows: 200
     filtered: 100.00
        Extra: Using index
2 rows in set, 1 warning (0.00 sec)

mysql> show warnings \G
*************************** 1. row ***************************
  Level: Note
   Code: 1003
Message: /* select#1 */ select (/* select#2 */ select 1 from `sakila`.`actor` limit 1) AS `(select 1 from sakila.actor limit 1)` from `sakila`.`film`

因为子查询是先执行内层查询的,推测,id越大,越先执行,个人推测,等我找完资料或者验证完毕之后再来填坑

  • from子句的子查询,也叫做派生表 。派生表的意思时语句执行时临时会生成一个匿名临时表,MYSQL内部通过别名在外层查询中引用这个临时表。
mysql> explain select actor_id from  (select actor_id from sakila.actor LIMIT 5) as der_1\G
*************************** 1. row ***************************
           id: 1
  select_type: PRIMARY     ---->说明有子查询或者UNION查询,而且这个是最外层的select子句
        table: <derived2>   --->这个就是派生表了, MYSQL内部先执行内层子查询select actor_id from sakila.actor LIMIT 5,将查询结果放入一个匿名临时表中,然后执行外层子查询时从匿名子查询中查询需要的数据
   partitions: NULL
         type: ALL
possible_keys: NULL
          key: NULL
      key_len: NULL
          ref: NULL
         rows: 5
     filtered: 100.00
        Extra: NULL
*************************** 2. row ***************************
           id: 2       -->select 1 from sakila.actor limit 1是内层子查询,所以id=2。内层子查询先执行。
  select_type: DERIVED  -- from 之后的SELECT子查询。
        table: actor
   partitions: NULL
         type: index
possible_keys: NULL
          key: idx_actor_last_name
      key_len: 137
          ref: NULL
         rows: 200
     filtered: 100.00
        Extra: Using index

MYSQL会从内到外递归执行from之后的子查询,并将查询结果放入一个匿名临时表中,这个临时表就叫做派生表,因为该临时表是从子查询中派生来的。

  • union子查询
mysql> explain SELECT actor_id from actor union SELECT first_name from actor\G
*************************** 1. row ***************************
           id: 1
  select_type: PRIMARY
        table: actor
   partitions: NULL
         type: index
possible_keys: NULL
          key: idx_actor_last_name
      key_len: 137
          ref: NULL
         rows: 200
     filtered: 100.00
        Extra: Using index
*************************** 2. row ***************************
           id: 2
  select_type: UNION  ---》UNION后面跟着的语句
        table: actor
   partitions: NULL
         type: ALL
possible_keys: NULL
          key: NULL
      key_len: NULL
          ref: NULL
         rows: 200
     filtered: 100.00
        Extra: NULL
*************************** 3. row ***************************
           id: NULL   ---》这个临时表不在原SQL中出现,因此他的id列是NULL
  select_type: UNION RESULT  ---》用来从UNION的匿名临时表检索结果的select被标记为UNION RESULT  
        table: <union1,2>  --》UNION结果总是将id1和id2结果放在一个匿名临时表中,之后MYSQL将结果读取到临时表之外
   partitions: NULL
         type: ALL  -- 全表扫描
possible_keys: NULL
          key: NULL
      key_len: NULL
          ref: NULL
         rows: NULL
     filtered: NULL
        Extra: Using temporary   ---优化器需要使用临时表

select_type

select_type 含义
SIMPLE 简单SELECT(不使用UNION或子查询等)
PRIMARY 如果查询有任何复杂的子部分,则将最外层的SELECT标记为PRIMARY
SUBQUERY 在SELECT列表中的SELECT(不在from中的子查询)
UNION UNION中的第二个或后面的SELECT语句
DEPENDENT UNION UNION中的第二个或后面的SELECT语句,依赖于外面的查询
UNION RESULT UNION的结果
DEPENDENT SUBQUERY 子查询中的第一个SELECT,依赖于外面的查询
DERIVED FROM子句的SELECT
MATERIALIZED 物化子查询
UNCACHEABLE SUBQUERY 不会被缓存的并且对于外部查询的每行都要重新计算的子查询
UNCACHEABLE UNION 属于不能被缓存的 UNION中的第二个或后面的SELECT语句

MATERIALIZED

  • 产生中间临时表(实体)
  • 临时表自动创建索引并和其他表进行关联,提高性能
  • 和子查询的区别式,优化器将可以进行MATERIALIZED 的语句自动
mysql> explain select film_id , (select rental_id from sakila.rental limit 1) from sakila.film AS der_2\G
*************************** 1. row ***************************
           id: 1
  select_type: PRIMARY
        table: der_2   --- sakila.film 的别名der_2
   partitions: NULL
         type: index   -- 索引扫描
possible_keys: NULL
          key: idx_fk_language_id
      key_len: 1
          ref: NULL
         rows: 1000
     filtered: 100.00
        Extra: Using index
*************************** 2. row ***************************
           id: 2
  select_type: SUBQUERY   --- 在SELECT列表中的SELECT
        table: rental
   partitions: NULL
         type: index   -- 索引扫描
possible_keys: NULL
          key: idx_fk_staff_id
      key_len: 1
          ref: NULL
         rows: 16008
     filtered: 100.00
        Extra: Using index
mysql> explain select film_id , (select @var1 from sakila.rental limit 1) from sakila.film AS der_2\G
*************************** 1. row ***************************
           id: 1
  select_type: PRIMARY
        table: der_2
   partitions: NULL
         type: index   -- 索引扫描
possible_keys: NULL
          key: idx_fk_language_id
      key_len: 1
          ref: NULL
         rows: 1000
     filtered: 100.00
        Extra: Using index
*************************** 2. row ***************************
           id: 2
  select_type: UNCACHEABLE SUBQUERY  -- @var1 的结果被缓存在一个ITem-cache中
        table: rental
   partitions: NULL
         type: index   -- 索引扫描
possible_keys: NULL
          key: idx_fk_staff_id
      key_len: 1
          ref: NULL
         rows: 16008
     filtered: 100.00
        Extra: Using index

table

  • 通常是用户操作的用户表
  • <unionM, N> UNION得到的结果表
  • 派生表,由id=N的语句产生
  • 子查询物化产生的表,由id=N的语句产生
mysql> explain select film.film_id from sakila.film inner join sakila.film_actor using(film_id) inner join sakila.actor using(actor_id);
+----+-------------+------------+
| id | select_type | table      | 
+----+-------------+------------+-
|  1 | SIMPLE      | actor      |
|  1 | SIMPLE      | film_actor | 
|  1 | SIMPLE      | film       |    -- 可以从table列中从上往下查询关联优化器查询时的关联顺序:先actor -> film_actor --> film
+----+-------------+------------+-

type

依据箭头,成本从小到大
在这里插入图片描述

  • ALL:按照索引次序一行一行的从头到尾扫描整张表
  • index:按照索引次序扫描整张表,和全表扫描不同的是,它只扫描索引,不会扫描其他行
    • 优点:不需要排序
    • 缺点:如果是按随机次序访问行,开销会很大
  • range:一个有限制的索引扫描–>从索引里的某一点,返回匹配这个值域的行,它不需要遍历全部索引
    • 比如between,where >,in(索引),or(索引)等
  • ref_or_null:ref的一个变体,它意味着MYSQL必须在初次查询的结果中进行第二次查询以找出NULL条目
  • ref:索引查找,返回所有匹配某个单个值得行
    • 缺点:可能会找到多个符合条件的行。
    • 只有当使用非唯一性索引或者唯一性索引的非唯一性前缀才会发生
    • 之所以叫做ref是因为索引需要和某个参考值比较。这个参考值可以是常数或者来自多表查询前一个表中的结果集
  • ef_ref:最多只返回一条符合条件的记录
  • NULL:MYSQL能在优化阶段分解查询语句,在执行阶段甚至用不着再访问表或者索引。

possible_keys

优化器可能使用到的索引:这个列表是优化早期创建的,因此有些索引可能会与后续优化过程是没有用的。---->揭示哪些索引有助于高效的查找

key

实际采用的索引:

(5)extra
在这里插入图片描述

  • Using filesort:可以使用复合索引将filesort进行优化。提高性能
  • Using index:比如使用覆盖索引
  • Using where: 使用where过滤条件
    Extra的信息是可以作为优化的提示,但是更多的是优化器优化的一种说明

猜你喜欢

转载自blog.csdn.net/zhizhengguan/article/details/86622765
今日推荐