1. 是什么?
它是一个关键字。我们知道我们写的SQL,执行之前要经过优化器的优化,所以我们写的SQL经过SQL优化器之后到底是怎么样的?这就可以通过explain关键字来查看。
2. 能干吗?
3. 怎么用?
语法:explain SQL
,explain SQL \G
,竖行显示,explain format=json SQL \G
,以json形式显示。比如我执行explain select * from tb_emp;
,就会出现如下结果:
执行计划
4. 执行计划包含的信息:
如上图,执行计划查出来后包含如下信息:
explain select * from t1,t2,t3 where ……
,假如执行结果如下:id | select_type | table |
---|---|---|
1 | simple | t1 |
1 | simple | t3 |
1 | simple | t2 |
可以看到t1、t2、t3的id都是1。id相同,表示从上到下执行。即先查t1,再查t3,最后查t2,而并非我们写的SQL的t1、t2、t3的顺序。
第二种,id递增。再比如我执行:
explain select t2.*
from t2
where id = ( select id
from t1
where id = (select t3.id from t3 where ……));
我们看到的顺序应该是t2、t1、t3,执行计划是:
id | select_type | table |
---|---|---|
1 | primary | t2 |
2 | subquery | t1 |
3 | subquery | t3 |
如果有子查询,id会递增,id越大的优先级越高,越先执行。比如上面顺序就应该是t3、t1、t2。
第三种,有些id相同,有些不同。比如我再执行:
explain select t2.*
from
(select t3.id from t3 where ……) temp1, t2
where temp1.id = t2.id;
id | select_type | table |
---|---|---|
1 | primary | <derived2> |
1 | primary | t2 |
2 | derived | t3 |
首先说一下derived是衍生的意思,就是临时表,即上面SQL语句中的temp1。还是id越大的越先执行,所以还是t3最先执行,然后id相同的从上到下执行,所以接下来是derived2,其实就是temp1,最后才是t2。
select_type | 含义 |
---|---|
simple | 简单查询,不包含子查询、union那些 |
primary | 语句中若包含任何复杂的子查询,最外层则被标记为primary |
subquery | 子查询 |
derived | 临时表 |
union | 语句中出现了union,那么union后面那个select就被标记为union |
union result | 从union表中获取结果的select |
type | 含义 |
---|---|
system(最优) | 表只有一行记录,所以用户建的表几乎不会出现这个,因为没有哪个表只存一条数据吧。 |
const | 表示通过索引一次就找到了。const用于比较primary key或者union索引,比如where条件后面跟的是主键,那就是const。 |
eq_ref | 唯一索引扫描,对于每个索引键,表中只有一条记录匹配。比如员工表tb_emp有一个字段deptId,表示部门的id,与部门表tb_dept的主键id建立了外键索引,并且tb_emp表中的每一条记录的deptId,在tb_dept表中只能找到一条记录,这种情况就是eq_ref,见下图[eq_ref] |
ref | 非唯一性索引扫描,返回某个值对应的所有行。比如一个部门有多个员工,用一个部门id去查,就可以查出多个员工,这就是ref。 |
range | 表示用索引在某一个范围搜索,用between或者in,比如,explain select * from tb_emp where id between 1 and 4; |
index | 全索引扫描,all是遍历全表,index是遍历索引树,所以比all快。explain select id from tb_emp;就是index |
all(最差) | 表示全表扫描,数据量百万以上必须优化 |
eq_ref
复合索引
ref
extra | 含义 |
---|---|
using filesort | 说明MySQL会对数据使用一个外部的索引排序,而不是用表内的索引顺序进行读取,这种文件内排序是很费时的。比如我建了一个复合索引idx_col1_col2_col3,执行select col1 from t1 where col1 = 'a' order by col3,我们建的复合索引是三个列,而这条sql中只使用了两个,col2没了,看它的执行计划就会发现,有using filesort。假如order by col2, col3,那就不会有。 |
using temporary | MySQL在对查询结果排序时新建了一个临时表处理数据,常见于order by和group by,这种情况性能更差。比如有张表我新建了索引idx_col1_col2,查询select col1 from t1 where col1 in('a', 'b') group by col2,这个就会出现using temporary,但是如果group by col1,col2,那就没问题了。 |
using index | 表示相应的select操作使用了覆盖索引,避免访问了表的数据行,效率不错。比如刚才的tb_emp表,我建立了idx_id_deptId索引,然后我执行select id, deptId from tb_emp,就是using index。 |
using where | 表明使用了where过滤条件 |
using join buffer | 使用了连接缓存 |
impossible where | where后面的条件总是false,比如where 1 = 2 |
select tables optimized away | 很少出现 |
distinct | 很少出现 |