explain查询计划,用来查看sql是否使用了索引,使用了多少索引,排序方式等。
type字段详细解释
NULL:一般在查询阶段不需要访问表,直接查索引即可。例如查询列最小值id的列
const,system:一般查询条件可以确定为一个常量,与primary key和unique key的列进行比较,因为只有一个值,所以只会匹配一行,读取速度非常快。
eq_ref:unique key或primary key索引的被连接使用,最多只会返回一条符合条件的记录
ref:相比eq_ref,不使用唯一索引,使用普通索引或者唯一索引部分前缀,可能会找到多个符合的记录
range:一般表示范围查找,in,between,<,>等操作
index:扫描索引就能拿到结果(不需要回表),一般为覆盖索引(查询字段中包含了where的条件,且where条件符合走索引的规范)
ALL:全表扫描,不走索引。这个一般会根据mysql的底层算法判断应该走索引还是全表。所以有时候走全表速度不一定比走索引慢
type_len计算规则
字符串,char(n)和varchar(n)在5.0.3之后n代表字符数,不是字节数,utf-8一个汉字3个字节。 char(n):3nvarchar(n):3n+2 (2个字节为储存字符串长度)extra详细
Using index覆盖索引:select查询的字段都在where的索引字段中,只用通过索引就能拿到结果而不用回表查。 explain select film_id from film_actor where film_id = 1 Using where:与Using index相反,查询的字段没有被where的索引覆盖。 explain select * from film_actor where actor_id = 1 Using index condition:select查询的列没有完全被where的索引覆盖,where条件是一个前导列的范围 explain select * from film_actor where film_id > 3 Using temporary:mysql需要建立一张临时表来处理。一般情况需要优化 查询actor表,actor表没有name索引 EXPLAIN SELECT DISTINCT name from actor 查询film表,film表有name索引 EXPLAIN SELECT DISTINCT name from film5. Using filesort:使用外部排序不走索引排序,数据比较少时会从内存中排序,否则在磁盘中完成排序,一般也是需要优化。
actor表 EXPLAIN SELECT name from actor ORDER BY name film表 EXPLAIN SELECT name from film ORDER BY name默认使用INNODB引擎。INNODB下,主键索引和数据使用b+tree数据结构组织在一个文件当中,多级索引则是单独一个文件,这里我们使用一个二级索引。
假设有index(a,b,c)
where语句 索引使用情况a=1使用了aa=1 and b=2使用了a,ba=1 and b=2 and c=3使用了a,b,ca=1 and c=3使用了a(b中断)a=1 and b>2 and c=3使用了a,ba=1 and b>=2 and c=3使用了a,b,c。个人认为使用=号更能确定范围,而使用>不能确定范围,mysql底层会认为纯粹使用>这样不确定的范围会走全表扫描效率比较高b=2 或 b=2 and c=3 或c=3不使用like这里总结一下like,like和>= 和<=类似,所以凡是like ‘k%’ 这样k开头的会走索引,还有一种情况’k%kk%’,这里使用了索引下推,最终也会走索引。 employee表,全值索引 explain select * from employees where name = 'LiLei' explain select * from employees where name = 'LiLei' and age = 10 explain select * from employees where name = 'LiLei' and age = 10 and position = 'sd'最左前缀原则:指where条件语句中,需要按照索引的顺序来查询,且不能跳过中间某一个索引
不在索引列上做任何操作(计算、函数、(自动or手动)类型转换),会导致索引失效而转向全表扫描
EXPLAIN SELECT * FROM employees WHERE left(name,3) = 'LiLei';4. 不能使用索引中范围条件右边的列,但是注意,使用>=可以走索引
EXPLAIN SELECT * FROM employees WHERE name= 'LiLei' AND age > 22 AND position ='xxx'; EXPLAIN SELECT * FROM employees WHERE name= 'LiLei' AND age >= 22 AND position ='manage r';5. 尽量使用覆盖索引 6. mysql在使用不等于(!=或者<>),not in ,not exists 的时候无法使用索引会导致全表扫描 < 小于、 > 大于、 <=、>= 这些,mysql内部优化器会根据检索比例、表大小等多个因素整体评估是否使用索引 7. is null,is not null 一般情况下也无法使用索引 8. like以通配符开头(’$abc…’)mysql索引失效会变成全表扫描操作,但是使用覆盖索引可以使用到索引,但是后面的索引会失效。
Mysql5.6以前这条查询语句会回表查找到所有like 'LiLei%'的数据,然后再通过age 和 position进行过滤。之后会每拿到一个 like ‘LiLei%’ 这样的数据就在内存中和后面的条件进行比对,所以这里依旧会用到索引(这里like如果和后面两个条件顺序打乱依旧会走索引)。
还有一种情况,这里我复制一张employees_copy1表,和employee表结构一样,里面有10w条数据,在数据量比较大的情况也会走索引
与in一样,在数据量大的情况的下会走索引
filesort使用临时文件进行排序,因为涉及到磁盘IO,因此出现fielsort的情况下都是需要优化sql的。
单路排序:一次性取出所有满足条件的字段,在sort buffer排序。双路排序:取出需要排序的字段和能定位数据行的id(主键,或者rowid),在sort buffer排好序后再回表把所有字段返回。Mysql通过比较系统变量max_length_for_sort_data(默认1024字节)来区分使用单路或者双路, max_length_for_sort_data <排序字段,单路 max_length_for_sort_data >排序字段,双路
因为第一条sql中,根据name排序数据量太大,mysql算法全表扫描会比索引快(需要回表查的时间啊成本更高),所以不会走索引。此时应该将数据量大的查询返回尽可能少的字段,走索引,然后关联查询。