Explain(执行计划)
EXPLAIN select (select 1 from tb_author where id=1) from (select * from tb_ book where id=1) der;
id
在多个 select 中,id 越大越先执行;如果 id 相同,上面的先执行。
select_type
-
derived 第一条执行的 sql 是 from 后面的子查询,该子查询只要在 from 后面,就会生成一张衍生表, 因此 der 的查询类型是 derived
-
subquery 在 select 之后 from 之前的子查询
-
primary 最外部的 select
-
simple 不包含子查询的简单查询
-
union 使用 union 进行的联合查询
table
当前正在查询的表名
type
type 列可以直观的判断出当前的 sql 语句的性能,type 里的取值和性能的优劣顺序如下:
null > system > const > eq_ref > ref > range > index > all
对于 SQL 优化来说,要尽量保证 type 列的值是属于 range 及以上级别。
- null
性能最好的,一般在使用了聚合函数操作索引列,结果直接从索引树获取即可,因此是性能最好。
- system
很少见,直接和一条记录进行匹配。
- const
使用主键索引或唯一索引和常量进行比较,这种性能非常好
- eq_ref
在进行多表连接查询时,如果查询条件使用了主键进行比较,那么当前查询类型是 eq_ref
EXPLAIN select * from tb_book_author left join tb_book on tb_book_author.book id = tb_book.id
- ref
简单查询:查询条件是普通列索引
EXPLAIN select * from tb_book where name='book1'
复杂查询:查询条件是普通列索引
EXPLAIN select book.id from tb_book left join tb_book_author on tb_book.id = tb_book_author.book_id
- range
使用索引进行范围查找
- index
查询没有条件判断,但是所有的数据都可以直接从索引树上获取
- all
没有使用索引,进行了全表扫描
possible keys
此次查询可能会用到的索引。MySQL 内部优化器会进行判断,如果查询走索引的性能比全表扫描的性能要差,那么内部优化器就让此次查询进行全表扫描(这样的判断依据我们可以通过 trace 工具来查看)
key
sql 语句实际使用的索引
rows
sql 语句可能要查询的数据条数
key_len
键的长度,通过这一列可以知道,当前查询命中了联合索引中的哪几列
extra
extra 列提供了额外的信息,够帮助我们判断当前 sql 是否使用了覆盖索引、文件排序、使用了索引进行查询条件等等的信息。
- Using index
使用了覆盖索引
- Using where
where 的条件使用了普通索引
- Using index condition
查询的列没有完全被索引覆盖,并且 where 条件中使用普通索引
- Using temporary
在没有索引的列上执行去重操作,需要临时表来实现;这种情况可以通过给列加索引进行优化
- Using filesort
MySQL 对数据进行排序,都会使用磁盘或借助内存来完成,涉及到两个概念:单路排序、双路排序
- Select tables optimized away
当直接在索引列上使用聚合函数,意味着不需要操作表
trace
在执行计划中,我们发现有的 sql 会走索引,有的 sql 即使明确使用了索引也不会走索引。这是因为 mysql 的内部优化器任务走索引的性能比全表扫描的性能要差,因此 mysql 内部优化器选择了使用全表扫描。依据来自于 trace 工具的结论。
set sess ion optimizer_trace="enabled=on", end_ markers_ in_ json=on; -- 开启 trace
select * from employees where name > 'a' order by position; --执行查询
select * from information_schema.OPTIMIZER_TRACE; --获得 trace 的分析结果