使用Explain关键字可以模拟优化器执行SQL语句,分析你的查询语句或是结构的性能瓶颈,在select语句执行增加explain关键字,MySQL会在查询上社招一个标记,执行查询会返回执行计划的信息,而不是执行这条SQL。
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);
表示对应行是简单还是复杂的查询
simple:简单查询。查询不包含子查询和union
primary:复杂查询中最外层的select
subquery:包含在select中的子查询(不在select子句中)
derived:包含在from子句中的子查询。MYSQL会将结果存放在一个临时表中,也称为派生表。
mysql> set session optimizer_switch='derived_merge=off'; #关闭mysql5.7新特性对衍生表的合并优化
mysql> explain select (select 1 from actor where id = 1) from (select * from film where id = 1) der;
mysql> explain select 1 union all select 1;
EXPLAIN SELECT min(id) from film
mysql> explain select * from film_actor left join film on film_actor.film_id = film.id;
mysql> explain select film_id from film left join film_actor on film.id = film_actor.film_id;
mysql> explain select * from actor where id > 1;
mysql> explain select * from film;
mysql> explain select * from actor;
这一列显示mysql在所有里使用的字节数,通过这个值可以具体算出使用了索引中的哪些列
key_len的计算规则
字符串,char(n)和varchar(n),5.0.3以后版本中,**n均代表字符数,而不是字节数,**如果是utf-8,一个数字或字母占1个字节,一个汉字占3个字节
数值类型
时间类型
如果字段运行为NULL,需要1字节记录是否为NULL
展示的是额外信息
Using index:使用覆盖索引
mysql> explain select film_id from film_actor where film_id = 1;
using where:使用where语句来处理结果,并且查询的列未被索引覆盖
mysql> explain select * from actor where name = 'a';
mysql> explain select * from film_actor where film_id > 1;
mysql> explain select distinct name from actor;
# name上存在索引
mysql> explain select distinct name from film;
mysql> explain select * from actor order by name;
CREATE TABLE `employees` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`name` varchar(24) NOT NULL DEFAULT '' COMMENT '姓名',
`age` int(11) NOT NULL DEFAULT '0' COMMENT '年龄',
`position` varchar(20) NOT NULL DEFAULT '' COMMENT '职位',
`hire_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '入职时间',
PRIMARY KEY (`id`),
KEY `idx_name_age_position` (`name`,`age`,`position`) USING BTREE
) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8 COMMENT='员工记录表';
INSERT INTO employees(name,age,position,hire_time) VALUES('LiLei',22,'manager',NOW());
INSERT INTO employees(name,age,position,hire_time) VALUES('HanMeimei', 23,'dev',NOW());
INSERT INTO employees(name,age,position,hire_time) VALUES('Lucy',23,'dev',NOW());
EXPLAIN SELECT * FROM employees WHERE name= 'LiLei';
EXPLAIN SELECT * FROM employees WHERE name= 'LiLei' AND age = 22 AND position ='manager';
EXPLAIN SELECT * FROM employees WHERE name= 'LiLei' AND age > 22 AND position ='manager'; ## 不会使用索引
解决like %abc%不能使用索引的情况
EXPLAIN SELECT name,age,position FROM employees WHERE name like '%Lei%';
如果不能使用覆盖索引,则使用其他搜索引擎
ALTER TABLE `employees` ADD INDEX `idx_age` (`age`) USING BTREE ;
explain select * from employees where age >=1 and age <=2000;
没走索引原因:mysql内部优化器会根据检索比例、表大小等多个因素整体评估是否使用索引。比如这个例子,可能是由于单次数据量查询过大导致优化器最终选择不走索引
优化方法:可以将大的范围拆分成多个小范围
explain select * from employees where age >=1 and age <=1000;
explain select * from employees where age >=1001 and age <=2000;
删除索引
ALTER TABLE `employees` DROP INDEX `idx_age`;
like KK%相当于=常量,%KK和%KK% 相当于范围