SQL explain函数解析

建表、插入数据

DROP TABLE IF EXISTS actor;
CREATE TABLE actor (
id int(11) NOT NULL,
name varchar(45) DEFAULT NULL,
update_time datetime DEFAULT NULL,
PRIMARY KEY (id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

INSERT INTO actor (id, name, update_time) VALUES (1,'a','2017-12-22 15:27:18'), (2,'b','2017-12-22 15:27:18'), (3,'c','2017-12-22 15:27:18');

DROP TABLE IF EXISTS film;
CREATE TABLE film (
id int(11) NOT NULL AUTO_INCREMENT,
name varchar(10) DEFAULT NULL,
PRIMARY KEY (id),
KEY idx_name (name)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

INSERT INTO film (id, name) VALUES (3,'film0'),(1,'film1'),(2,'film2');


DROP TABLE IF EXISTS film_actor;
CREATE TABLE film_actor (
id int(11) NOT NULL,
film_id int(11) NOT NULL,
actor_id int(11) NOT NULL,
remark varchar(255) DEFAULT NULL,
PRIMARY KEY (id),
KEY idx_film_actor_id (film_id,actor_id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

INSERT INTO film_actor (id, film_id, actor_id) VALUES (1,1,1),(2,1,2),(3,2,1);

运行explain函数

explain select * from actor where id = 1;

结果分析:

id:每一句select都有一个id;id列数值越大,执行的优先级越高;id相同,从上往下执行;id为null最后执行

select_type(查询类型):有两种,分别是simple(简单查询)和primary(复杂查询)

【简单查询】:只用到select 单表的增删查改

【复杂查询】:1、简单子查询(subquery)、from中的子查询(derived)、union、join连接查询

Derived table实际上是一种特殊的subquery

table(表):正在查询的表

type(关联类型或访问类型):最优到最差的排序

system > const > eq_ref > ref > range > index > ALL

一般来说要达到range,最好达到ref

(1)type为null

explain select min(id) from film;

  id是索引列,在索引列选最小值,可以直接查询索引完成,不需要再访问表

(2)type为const和system

system是特殊的const,表示只有一行匹配时为system

explain select * from actor where id = 1;
show warnings;

 show  warnings的结果:

可以看出,把查询部分优化,并转成一个常量。const和system常用于当主键或者唯一键的列和常数比较。

(3)type为eq_ref

explain select * from film_actor left join film on film_actor.film_id = film.id;

主键或者唯一索被连接时使用,最多只会返回一条记录

(4)type为ref

explain select * from film where name = “film1”;

 此时name为普通索引

(5)type为range

in(), between ,> ,<, >=

(6)type为index

扫描整个表的索引,比如:explain select * from film;

(7)type为all:全表扫描

possible_keys(可能使用什么索引来找):1、null(全表),可以看where用到的列能不能建索引

2、primary主键

key(用了什么索引来找):1、null(没有用索引);如果想强制用possible_keys可以在查询中用force index,忽视的话用ignore index

key_len(索引的字节数):

char(n) n字节

varchar(n):汉字ascii1个字-2字节,utf-8-3字节,unicode-2,

英文:ascii-1字节,utf-8-1字节,unicode-2字节;

长度3n+相应字节

tinyint:1字节
smallint:2字节
int:4字节
bigint:8字节  
时间类型

date:3字节
timestamp:4字节
datetime:8字节

字段为Null,也需要1字节记录

注意:

1、索引最大长度768字节,字符串过长,会采用左前缀索引处理,将前半部分提取

2、ken_len越小越好

ref(选择哪个列or常数-和key一起选择行)

row:估计要读取和检测的行,注意:不是结果集的行

extra:

1、using index 查询的列被索引覆盖,并且where筛选条件是索引的前导列(最左侧索引),是性能高的表现。

2、using where 查询的列未被索引覆盖,where筛选条件非索引的前导列

3、Using where Using index:查询的列被索引覆盖,并且where筛选条件是索引列之一但不是索引的前导列,意味着无法直接通过索引查找来查询到符合条件的数据

4、 Using where Using index:查询的列被索引覆盖,并且where筛选条件是索引列之一但不是索引的前导列,意味着无法直接通过索引查找来查询到符合条件的数据。

比如:explain select film_id from film_actor where actor_id = 1;

film_id和actor_id是联合索引

5、Using index condition:与Using where类似,查询的列不完全被索引覆盖,where条件中是一个前导列的范围

mysql> explain select * from film_actor where film_id > 1;

6、Using temporary:mysql需要创建一张临时表来处理查询。出现这种情况一般是要进行优化的,首先是想到用索引来优化。

actor.name没有索引,此时创建了张临时表来distinct mysql> explain select distinct name from actor;

7、Using filesort:mysql 会对结果使用一个外部索引排序,而不是按索引次序从表里读取行。此时mysql会根据联接类型浏览所有符合条件的记录,并保存排序关键字和行指针,然后排序关键字并按顺序检索行信息。这种情况下一般也是要考虑使用索引来优化的。

actor.name未创建索引,会浏览actor整个表,保存排序关键字name和对应的id,然后排序name并检索行记录 mysql> explain select * from actor order by name;

索引使用时要注意:

1、全值匹配,等于号

2、最佳左前缀法。查询从索引最左列开始,不跳过中间索引列

3、不在索引列作计算、函数

4、尽量使用覆盖索引(只访问索引的查询(索引列包含查询列)),减少select *语句

5、在使用不等于(!=或者<>)的时候无法使用索引会导致全表扫描

6、is null,is not null 也无法使用索引

7、like以通配符开头(’$abc…’)mysql索引失效会变成全表扫描操作

8、字符串不加单引号索引失效

9、少用or或in, 用它查询时, 非主键字段会失效, 主键索引有时生效, 有时不生效, 跟数据量有关, 具体还看mysql的查询优化结果

10、like KK%相当于=常量,%KK和%KK% 相当于范围

猜你喜欢

转载自blog.csdn.net/kanseu/article/details/124725046