Extra 是 EXPLAIN 输出中另外一个很重要的列,该列显示MySQL在查询过程中的一些详细信息
类型 | 说明 |
Using filesort | MySQL有两种方式可以生成有序的结果:通过排序操作或者使用索引。当Extra中出现了Using filesort 说明使用了前者,但注意虽然叫 filesort 但并不是一定就是用了磁盘文件来进行排序,也可能是在内存里完成的。当出现排序,可以通过添加合适的索引来改进性能,用索引来为查询结果排序。 |
Using temporary | 用临时表保存中间结果,常用于 GROUP BY 操作中,一般看到它说明查询需要优化了 |
Using index | 使用索引覆盖的情况 |
Using index condition | 发生索引条件下推(IndexCondition Pushdown)的情况 |
Using where | 全表扫描的时候,MySQL服务层应用 where 条件过滤数据;使用索引访问数据,但是 where 子句中有除了改索引包含的字段之外的条件时 |
Using join buffer | 当关联查询使用 Block Nested Loop 算法或者 Batched Key Access 算法,会把对驱动表查询的结果集放到 join buffer 中 |
distinct | 优化 distinct 操作,在找到第一匹配的元组后即停止找同样值的动作 |
LooseScan | 表示使用了 Semi-join LooseScan 策略优化子查询 |
FirstMatch | 表示使用了 Semi-join FirstMatch 策略优化子查询 |
Start temporary、End temporary | 表示使用了 Semi-join DuplicateWeedout 策略优化子查询 |
使用索引覆盖的情况下,执行计划的 extra 会显示为 "Using index":
比如:
有组合索引:idx_a
(first_name
,last_name
,birth_date
)
mysql> explain select first_name,last_name,birth_date from employees where \
first_name='Mayuri' and last_name like 'Alpay' and birth_date > '1968-01-01'\G
*************************** 1. row ***************************
id: 1
select_type: SIMPLE
table: employees
partitions: NULL
type: range
possible_keys: idx_a
key: idx_a
key_len: 127
ref: NULL
rows: 1
filtered: 100.00
Extra: Using where; Using index
查询数据时如果使用 index condition down 索引条件下推就会在执行计划的 extra 字段中出现 "Using index condition"。
使用二级索引查找数据时,where 条件中属于索引一部分但无法使用索引的条件(比如 like '%abc' 左侧字符不确定),MySQL也会把这部分判断条件下推到存储引擎层,筛选之后再进行回表,这样回表时需要查找的数据就更少。
索引条件下推的特点:
有一个组合索引:idx_a
(first_name
,last_name
,birth_date
)
SQL:
mysql> explain select * from employees where first_name='Mayuri' and last_name like '%Alpay'\G
*************************** 1. row ***************************
id: 1
select_type: SIMPLE
table: employees
partitions: NULL
type: ref
possible_keys: idx_a
key: idx_a
key_len: 58
ref: const
rows: 230
filtered: 11.11
Extra: Using index condition
1 row in set, 1 warning (0.00 sec)
查询的 where 子句中 first_name='Mayuri' 条件可以使用到二级索引 idx_a,而 last_name like '%Alpay' 条件最左的字符不固定所以不能使用二级索引。索引下推的执行过程是:
有一个组合索引:idx_a
(first_name
,last_name
,birth_date
)
SQL: select * from employees where first_name > 'Mayuri' and last_name = 'Alpay';
在索引树上 first_name > 'Mayuri' 的数据行,对于 last_name 的值来说是无序的。所以搜索索引树时,只能用 first_name > 'Mayuri' 来找出数据,然后再把 last_name = 'Alpay' 这个条件下推到 innodb 层筛选数据。
有一个组合索引:idx_a
(first_name
,last_name
,birth_date
)
SQL为:
mysql> explain select * from employees where first_name='Mayuri' and last_name > 'Alpay'\G
*************************** 1. row ***************************
id: 1
select_type: SIMPLE
table: employees
partitions: NULL
type: range
possible_keys: idx_a
key: idx_a
key_len: 124
ref: NULL
rows: 226
filtered: 100.00
Extra: Using index condition
虽然这里显示了“Using index condition”,但实际上是不需要做索引条件下推的,因为索引的第一个字段固定,对于 last_name 字段值来说也是有序的。这属于一个“bug”,特地考古找到了丁奇老师回复的一条评论:
如果是索引覆盖不需要回表,即使发生索引条件下推,也不会出现 "Using index condition":
mysql> explain select first_name,last_name,birth_date from employees where
first_name > 'Mayuri' and last_name > 'Alpay'\G
*************************** 1. row ***************************
id: 1
select_type: SIMPLE
table: employees
partitions: NULL
type: range
possible_keys: idx_a
key: idx_a
key_len: 124
ref: NULL
rows: 226
filtered: 100.00
Extra: Using where; Using index
总的来说,只要是用到 index filter,就会发生索引条件下推。但不一定出现 Using index condition 就一定发生了索引条件下推。关于 index filter 的概念,详见:SQL中的where条件,在数据库中提取与应用浅析
就是前面说的 MySQL 服务层可以把属于索引的一部分但又无法使用索引的条件下推到存储引擎层,而其他条件还是得在 MySQL 服务层应用来过滤存储引擎层返回的数据。当出现这的情况,执行计划的 extra 字段就会出现"Using where",它可以和"Using index" 一起出现,也可以和"Using index condition" 一起出现。
mysql> explain select emp_no,first_name,last_name from employees where hire_date = '1959-12-06'\G
*************************** 1. row ***************************
id: 1
select_type: SIMPLE
table: employees
partitions: NULL
type: ALL
possible_keys: NULL
key: NULL
key_len: NULL
ref: NULL
rows: 299454
filtered: 10.00
Extra: Using where
mysql> explain select emp_no,first_name,last_name from employees where first_name='Mayuri' and hire_date = '1959-12-06'\G
*************************** 1. row ***************************
id: 1
select_type: SIMPLE
table: employees
partitions: NULL
type: ref
possible_keys: idx_a
key: idx_a
key_len: 58
ref: const
rows: 230
filtered: 10.00
Extra: Using where
mysql> explain select first_name,last_name,birth_date from employees where first_name='Mayuri' and last_name like '%Alpay'\G
*************************** 1. row ***************************
id: 1
select_type: SIMPLE
table: employees
partitions: NULL
type: ref
possible_keys: idx_a
key: idx_a
key_len: 58
ref: const
rows: 230
filtered: 11.11
Extra: Using where; Using index
mysql> explain select * from employees where first_name='Mayuri' and last_name like '%Alpay' and hire_date>'1969-01-01'\G
*************************** 1. row ***************************
id: 1
select_type: SIMPLE
table: employees
partitions: NULL
type: ref
possible_keys: idx_a
key: idx_a
key_len: 58
ref: const
rows: 230
filtered: 3.70
Extra: Using index condition; Using where
https://www.jianshu.com/p/d9b13ca96f72
https://blog.xqlee.com/article/2504231304514736.html