Explain 详解
-
Explain 作用
- 查看表的读取顺序
- 数据读取操作的操作类型
- 查看哪些索引可使用
- 查看使用使用的索引
- 查看表之间的引用
- 查看每张表有多少行被优化器执行
-
Explain 使用方法
Explain + sql e.g. Explain select * from test; mysql> explain select * from test; +----+-------------+------------+------------+------+---------------+------+---------+------+------+----------+-------+ | id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra | +----+-------------+------------+------------+------+---------------+------+---------+------+------+----------+-------+ | 1 | SIMPLE | test | NULL | ALL | NULL | NULL | NULL | NULL | 5 | 100.00 | NULL | +----+-------------+------------+------------+------+---------------+------+---------+------+------+----------+-------+ 1 row in set, 1 warning (0.00 sec)
-
Explain 字段
-
id:
select
查询的序列号, 包含一组数字: 标示查询中执行select自己或者操作表的顺序-
id 相同, 执行顺序从上往下
mysql> Explain select * from employee e, department d, customer c where e.dep_id =d.id and e.cus_id = c.id; +----+-------------+-------+------------+--------+---------------+---------+---------+---------------+------+----------+----------------------------------------------------+ | id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra | +----+-------------+-------+------------+--------+---------------+---------+---------+---------------+------+----------+----------------------------------------------------+ | 1 | SIMPLE | c | NULL | ALL | PRIMARY | NULL | NULL | NULL | 1 | 100.00 | NULL | | 1 | SIMPLE | e | NULL | ALL | NULL | NULL | NULL | NULL | 8 | 12.50 | Using where; Using join buffer (Block Nested Loop) | | 1 | SIMPLE | d | NULL | eq_ref | PRIMARY | PRIMARY | 4 | test.e.dep_id | 1 | 100.00 | NULL | +----+-------------+-------+------------+--------+---------------+---------+---------+---------------+------+----------+----------------------------------------------------+ 3 rows in set, 1 warning (0.00 sec)
-
id 不同: 如果是子查询, id序号会递增, id值越大优先级越高, 优先被执行。
mysql> explain select * from department where id = (select id from employee where id = (select id from customer where id = 1)); +----+-------------+------------+------------+-------+---------------+---------+---------+-------+------+----------+-------------+ | id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra | +----+-------------+------------+------------+-------+---------------+---------+---------+-------+------+----------+-------------+ | 1 | PRIMARY | department | NULL | const | PRIMARY | PRIMARY | 4 | const | 1 | 100.00 | NULL | | 2 | SUBQUERY | employee | NULL | const | PRIMARY | PRIMARY | 4 | const | 1 | 100.00 | Using index | | 3 | SUBQUERY | customer | NULL | const | PRIMARY | PRIMARY | 4 | const | 1 | 100.00 | Using index | +----+-------------+------------+------------+-------+---------------+---------+---------+-------+------+----------+-------------+ 3 rows in set, 1 warning (0.00 sec)
-
-
select_type: 查询类型, 主要区别普通查询, 联合查询, 子查询等复杂的查询
- SIMPLE: 简单的
select
查询, 不包含子查询或者union
mysql> explain select * from department; +----+-------------+------------+------------+------+---------------+------+---------+------+------+----------+-------+ | id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra | +----+-------------+------------+------------+------+---------------+------+---------+------+------+----------+-------+ | 1 | SIMPLE | department | NULL | ALL | NULL | NULL | NULL | NULL | 5 | 100.00 | NULL | +----+-------------+------------+------------+------+---------------+------+---------+------+------+----------+-------+ 1 row in set, 1 warning (0.00 sec)
- SIMPLE: 简单的
-
PRIMARY: 查询中包含任何的复杂的子查询, 最外层被标记为
primary
mysql> explain select * from employee where dep_id = (select id from department where id = 1); +----+-------------+------------+------------+-------+---------------+---------+---------+-------+------+----------+-------------+ | id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra | +----+-------------+------------+------------+-------+---------------+---------+---------+-------+------+----------+-------------+ | 1 | PRIMARY | employee | NULL | ALL | NULL | NULL | NULL | NULL | 8 | 12.50 | Using where | | 2 | SUBQUERY | department | NULL | const | PRIMARY | PRIMARY | 4 | const | 1 | 100.00 | Using index | +----+-------------+------------+------------+-------+---------------+---------+---------+-------+------+----------+-------------+ 2 rows in set, 1 warning (0.00 sec)
-
SUBQUERY: 子查询
-
DERIVED: 代表着衍生表(虚拟表), 把结果放在衍生表中
mysql> explain select * from department d,(select * from(select dep_id from employee group by dep_id) t2 ) t where d.id = t.dep_id; +----+-------------+------------+------------+------+---------------+-------------+---------+-----------+------+----------+---------------------------------+ | id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra | +----+-------------+------------+------------+------+---------------+-------------+---------+-----------+------+----------+---------------------------------+ | 1 | PRIMARY | d | NULL | ALL | PRIMARY | NULL | NULL | NULL | 5 | 100.00 | NULL | | 1 | PRIMARY | <derived3> | NULL | ref | <auto_key0> | <auto_key0> | 5 | test.d.id | 2 | 100.00 | Using index | | 3 | DERIVED | employee | NULL | ALL | NULL | NULL | NULL | NULL | 8 | 100.00 | Using temporary; Using filesort | +----+-------------+------------+------------+------+---------------+-------------+---------+-----------+------+----------+---------------------------------+ 3 rows in set, 1 warning (0.00 sec)
-
UNION: 使用
union
-
UNION RESULT: 使用
union
, 最后显示的结果集mysql> explain select id from department union select id from employee; +----+--------------+------------+------------+-------+---------------+---------+---------+------+------+----------+-----------------+ | id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra | +----+--------------+------------+------------+-------+---------------+---------+---------+------+------+----------+-----------------+ | 1 | PRIMARY | department | NULL | index | NULL | PRIMARY | 4 | NULL | 5 | 100.00 | Using index | | 2 | UNION | employee | NULL | index | NULL | PRIMARY | 4 | NULL | 8 | 100.00 | Using index | | NULL | UNION RESULT | <union1,2> | NULL | ALL | NULL | NULL | NULL | NULL | NULL | NULL | Using temporary | +----+--------------+------------+------------+-------+---------------+---------+---------+------+------+----------+-----------------+ 3 rows in set, 1 warning (0.03 sec)
-
-
-
table: 显示这一样查询是关于哪张表的
-
partitions: 如果查询是基于分区表的话,会显示访问的分区
-
type: 访问类型排序(性能从上到下越来越差,)
-
system
- 表中有一行记录(系统表, 表只有一行,
MyISAM
引擎), 这是const
类型的特例, 平时不会出现
- 表中有一行记录(系统表, 表只有一行,
-
const
-
表示通过索引一次就找到结果
-
用于比较 primary 或者 unique 索引。
-
常量连接,表最多只有一行匹配,通用用于主键或者唯一索引比较时
mysql> explain select * from employee where id = 1; +----+-------------+----------+------------+-------+---------------+---------+---------+-------+------+----------+-------+ | id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra | +----+-------------+----------+------------+-------+---------------+---------+---------+-------+------+----------+-------+ | 1 | SIMPLE | employee | NULL | const | PRIMARY | PRIMARY | 4 | const | 1 | 100.00 | NULL | +----+-------------+----------+------------+-------+---------------+---------+---------+-------+------+----------+-------+ 1 row in set, 1 warning (0.00 sec)
-
-
eq_ref
-
唯一性索引扫描
-
对于每个索引键, 表中只有一条记录与之匹配
-
常见于主键或者唯一索引扫描
-
每次与之前的表合并行都只在该表读取一行,这是除了system,const之外最好的一种,特点是使用=,而且索引的所有部分都参与join且索引是主键或非空唯一键的索引
mysql> explain select * from employee e, department d where e.id = d.id; +----+-------------+-------+------------+--------+---------------+---------+---------+-----------+------+----------+-------+ | id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra | +----+-------------+-------+------------+--------+---------------+---------+---------+-----------+------+----------+-------+ | 1 | SIMPLE | d | NULL | ALL | PRIMARY | NULL | NULL | NULL | 5 | 100.00 | NULL | | 1 | SIMPLE | e | NULL | eq_ref | PRIMARY | PRIMARY | 4 | test.d.id | 1 | 100.00 | NULL | +----+-------------+-------+------------+--------+---------------+---------+---------+-----------+------+----------+-------+ 2 rows in set, 1 warning (0.00 sec)
-
-
ref
- 非唯一性索引扫描, 返回匹配某个单独值的所有行
- 本质上也是一种索引访问
- 返回所有匹配摸个单独值的行
- 可能会找到多个符合条件的行
- 如果每次只匹配少数行,那就是比较好的一种,使用=或<=>,可以是左覆盖索引或非主键或非唯一键
-
range
- 范围查询
-
index
- 和all 是一种类型, 只不过是扫描了索引树
-
All
- 扫描全表
-
-
possible_keys: 可能使用到的索引
-
key: 实际使用的索引
-
ken_len: 表示索引使用的字节数,根据这个值可以判断索引的使用情况,特别是在组合索引的时候,判断该索引有多少部分被使用到非常重要
-
ref: 哪些列或者常量被用做索引列上的值
-
rows: 根据表的统计信息和索引的使用情况,大致估算查询结果所需要读取记录的行数
-
filtered: 表示示存储引擎返回的数据在server层过滤后,剩下多少满足查询的记录数量的比例
-
Extra:
-
using where:
- SQL使用了where条件过滤数据。(需要借鉴 type 确定效率)
-
Using index:
- SQL所需要返回的所有列数据均在一棵索引树上,而无需访问实际的行记录(效率高)
-
Using index condition:
- 确实命中了索引,但不是所有的列数据都在索引树上,还需要访问实际的行记录(效率一般)
-
Using filesort:
- 得到所需结果集,需要对所有记录进行文件排序(效率低)
-
Using temporary:
- 需要建立临时表(temporary table)来暂存中间结果(效率低)
-
Using join buffer (Block Nested Loop):
- 需要进行嵌套循环计算, 即内外层
type
都是 all. (效率低)
- 需要进行嵌套循环计算, 即内外层
-