Extrah是为了提供一些附加的信息 , 可以通过该信息来判断Mysql到底要如何执行给定的语句
No table used
- 当查询语句没有from子句时会提示该信息
-
Impossible WHERE
查询语句的where条件永远是FALSE
mysql> EXPLAIN SELECT * FROM s1 WHERE 1 != 1;
No matching max/min row
使用MIN / MAX聚合函数 , 但是其where条件并没有查询到相应的信息
mysql> EXPLAIN SELECT MIN(key1) FROM s1 WHERE key1 = ‘abcdefg’;
Using index
使用到我条件列覆盖到索引的时候
mysql> EXPLAIN SELECT key1 FROM s1 WHERE key1 = ‘a’;
Using index condition
出现了索引列 , 但是却无法使用索引
- SELECT * FROM s1 WHERE key1 > ‘z’ AND key1 LIKE ‘%a’;
- 首先key1是索引列 , 通过二级索引检索 key1 > ‘ z’ , 找到二级索引记录的id
- 此步操作通过改进 , 在查询到二级索引记录的id的时候 , 先去匹配看是否满足后面条件 , 如果满足就返回 , 不满足再回表 , 减少随机IO时间
- 然后通过二级索引的id进行回表 , 查询 key1 like ‘%a’
- 首先key1是索引列 , 通过二级索引检索 key1 > ‘ z’ , 找到二级索引记录的id
像这种使用索引条件下推 (Index condition pushdown) 的查询语句 , 就会显示Using index condition的信息
Using where
当查询扫描全表 , 并且使用到了改表包含的where条件
mysql> EXPLAIN SELECT * FROM s1 WHERE common_field = ‘a’;
Using join buffer (Block Nested Loop)
当被驱动表无法有效利用索引 , Mysql会为其分配一块 join buffer的内存区域 , 是一种 基于块的循环嵌套算法
- mysql> EXPLAIN SELECT * FROM s1 INNER JOIN s2 ON s1.common_field = s2.common_field;
- 这段sql的执行计划中 ,s2的extra信息显示为 Using where,Using join buffer(Block Nested Loop)
- 首先在s2无法有效利用到索引的情况下 , 就使用了join buffer来减少IO的次数
- 其次 , 在联查的时候 , s1. = s2. , 那么就意味着s2此时是一个常量 , 所以提示到了Using where
余下的还有别的extra的附加信息 , 但是不想写了….. 感觉常见的就这几个吧 , 后续如果有经常遇到的再补充吧
Json格式
- 在语句中加上 FORMAT = JSON可以查看执行计划中”成本”的一环
mysql> EXPLAIN FORMAT=JSON SELECT * FROM s1 INNER JOIN s2 ON s1.key1 = s2.key2 WHERE s1.common_field = ‘a’\G
EXPLAIN: {"query_block": {"select_id": 1, # 整个查询语句只有1个SELECT关键字,该关键字对应的id号为1"cost_info": {"query_cost": "3197.16" # 整个查询的执行成本预计为3197.16},"nested_loop": [ # 几个表之间采用嵌套循环连接算法执行# 以下是参与嵌套循环连接算法的各个表的信息{"table": {"table_name": "s1", # s1表是驱动表"access_type": "ALL", # 访问方法为ALL,意味着使用全表扫描访问"possible_keys": [ # 可能使用的索引"idx_key1"],"rows_examined_per_scan": 9688, # 查询一次s1表大致需要扫描9688条记录"rows_produced_per_join": 968, # 驱动表s1的扇出是968"filtered": "10.00", # condition filtering代表的百分比"cost_info": {"read_cost": "1840.84", # 稍后解释"eval_cost": "193.76", # 稍后解释"prefix_cost": "2034.60", # 单次查询s1表总共的成本"data_read_per_join": "1M" # 读取的数据量},"used_columns": [ # 执行查询中涉及到的列"id","key1","key2","key3","key_part1","key_part2","key_part3","common_field"],# 对s1表访问时针对单表查询的条件"attached_condition": "((`xiaohaizi`.`s1`.`common_field` = 'a') and (`xiaohaizi`.`s1`.`key1` is not null))"}},{"table": {"table_name": "s2", # s2表是被驱动表"access_type": "ref", # 访问方法为ref,意味着使用索引等值匹配的方式访问"possible_keys": [ # 可能使用的索引"idx_key2"],"key": "idx_key2", # 实际使用的索引"used_key_parts": [ # 使用到的索引列"key2"],"key_length": "5", # key_len"ref": [ # 与key2列进行等值匹配的对象"xiaohaizi.s1.key1"],"rows_examined_per_scan": 1, # 查询一次s2表大致需要扫描1条记录"rows_produced_per_join": 968, # 被驱动表s2的扇出是968(由于后边没有多余的表进行连接,所以这个值也没啥用)"filtered": "100.00", # condition filtering代表的百分比# s2表使用索引进行查询的搜索条件"index_condition": "(`xiaohaizi`.`s1`.`key1` = `xiaohaizi`.`s2`.`key2`)","cost_info": {"read_cost": "968.80", # 稍后解释"eval_cost": "193.76", # 稍后解释"prefix_cost": "3197.16", # 单次查询s1、多次查询s2表总共的成本"data_read_per_join": "1M" # 读取的数据量},"used_columns": [ # 执行查询中涉及到的列"id","key1","key2","key3","key_part1","key_part2","key_part3","common_field"]}}]}}1 row in set, 2 warnings (0.00 sec)
