上一篇为大家介绍了MySQL中索引的存储结构已经索引类型和什么时候会用到索引等相关知识,想了解详细,请点击这里。这一篇将为大家分享如何用EXPLAIN关键字来分析sql语句的执行方式并预估效率,从而进行针对性的优化。
有时候我们写好了一条语句,想确认是不是会按我们想要的顺序或者有没有用到我们想让他用到的索引,这时候就可以用explain关键字了。
为了演示不同场景,我们准备以下四张表:
DROP TABLE IF EXISTS `user`;
CREATE TABLE `user` (
`id` INT(3) DEFAULT NULL,
`name` VARCHAR(20) DEFAULT NULL,
`job_id` INT(3) DEFAULT NULL,
`detail_id` INT(3) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=INNODB DEFAULT CHARSET=utf8;
INSERT INTO `user`(`id`,`name`,`job_id`,`detail_id`) VALUES (1,'张1',11,111);
INSERT INTO `user`(`id`,`name`,`job_id`,`detail_id`) VALUES (2,'张2',22,222);
INSERT INTO `user`(`id`,`name`,`job_id`,`detail_id`) VALUES (3,'张3',33,333);
INSERT INTO `user`(`id`,`name`,`job_id`,`detail_id`) VALUES (4,'张4',44,444);
INSERT INTO `user`(`id`,`name`,`job_id`,`detail_id`) VALUES (5,'张5',55,555);
INSERT INTO `user`(`id`,`name`,`job_id`,`detail_id`) VALUES (6,'张6',66,666);
INSERT INTO `user`(`id`,`name`,`job_id`,`detail_id`) VALUES (7,'张7',77,777);
INSERT INTO `user`(`id`,`name`,`job_id`,`detail_id`) VALUES (8,'张8',88,888);
INSERT INTO `user`(`id`,`name`,`job_id`,`detail_id`) VALUES (9,'张9',99,999);
INSERT INTO `user`(`id`,`name`,`job_id`,`detail_id`) VALUES (10,'张10',1010,101010);
DROP TABLE IF EXISTS `user_job`;
CREATE TABLE `user_job` (
`id` INT(3) DEFAULT NULL,
`job_name` VARCHAR(20) DEFAULT NULL,
`uid` INT(3) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=INNODB DEFAULT CHARSET=utf8;
INSERT INTO `user_job`(`id`,`job_name`,`uid`) VALUES (11,'CEO',1);
INSERT INTO `user_job`(`id`,`job_name`,`uid`) VALUES(22,'CTO',2);
INSERT INTO `user_job`(`id`,`job_name`,`uid`) VALUES (33,'mannger',3);
INSERT INTO `user_job`(`id`,`job_name`,`uid`) VALUES (44,'CEO',4);
INSERT INTO `user_job`(`id`,`job_name`,`uid`) VALUES(55,'CTO',5);
INSERT INTO `user_job`(`id`,`job_name`,`uid`) VALUES (66,'mannger',6);
INSERT INTO `user_job`(`id`,`job_name`,`uid`) VALUES (77,'CEO',7);
INSERT INTO `user_job`(`id`,`job_name`,`uid`) VALUES(88,'CTO',8);
INSERT INTO `user_job`(`id`,`job_name`,`uid`) VALUES (99,'mannger',9);
INSERT INTO `user_job`(`id`,`job_name`,`uid`) VALUES (1010,'CEO',10);
DROP TABLE IF EXISTS `user_detail`;
CREATE TABLE `user_detail` (
`id` INT(3) DEFAULT NULL,
`describe` VARCHAR(200) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=INNODB DEFAULT CHARSET=utf8;
INSERT INTO `user_detail`(`id`,`describe`) VALUES (111,'描述1');
INSERT INTO `user_detail`(`id`,`describe`) VALUES (222,'描述2');
INSERT INTO `user_detail`(`id`,`describe`) VALUES (333,'描述3');
INSERT INTO `user_detail`(`id`,`describe`) VALUES (444,'描述4');
INSERT INTO `user_detail`(`id`,`describe`) VALUES (555,'描述5');
INSERT INTO `user_detail`(`id`,`describe`) VALUES (666,'描述6');
INSERT INTO `user_detail`(`id`,`describe`) VALUES (777,'描述7');
INSERT INTO `user_detail`(`id`,`describe`) VALUES (888,'描述8');
INSERT INTO `user_detail`(`id`,`describe`) VALUES (999,'描述9');
INSERT INTO `user_detail`(`id`,`describe`) VALUES (101010,'描述10');
DROP TABLE IF EXISTS `test`;
CREATE TABLE `test` (
`id` int(5) NOT NULL AUTO_INCREMENT,
`name` varchar(50) DEFAULT NULL,
`company` varchar(20) DEFAULT NULL,
`age` tinyint(2) DEFAULT NULL,
`create_time` datetime DEFAULT NULL,
PRIMARY KEY (`id`),
KEY `name_index` (`name`)
) ENGINE=InnoDB AUTO_INCREMENT=123 DEFAULT CHARSET=utf8;
insert into `test` (`id`, `name`, `company`, `age`, `create_time`) values('1','张一','huawei','18','2020-05-29 12:36:11');
insert into `test` (`id`, `name`, `company`, `age`, `create_time`) values('2','张二','huawei','19','2020-05-29 12:36:13');
insert into `test` (`id`, `name`, `company`, `age`, `create_time`) values('3','张三','huawei','20','2020-05-29 12:36:15');
insert into `test` (`id`, `name`, `company`, `age`, `create_time`) values('4','张四','huawei','22','2020-05-29 12:36:16');
insert into `test` (`id`, `name`, `company`, `age`, `create_time`) values('5','李一','baidu','22','2020-05-29 12:36:18');
insert into `test` (`id`, `name`, `company`, `age`, `create_time`) values('6','李二','huawei','22','2020-05-29 12:36:24');
insert into `test` (`id`, `name`, `company`, `age`, `create_time`) values('7','李三','baidu','22','2020-05-29 12:36:25');
insert into `test` (`id`, `name`, `company`, `age`, `create_time`) values('8','李四','baidu','26','2020-05-29 12:36:28');
insert into `test` (`id`, `name`, `company`, `age`, `create_time`) values('9','李五','baidu','27','2020-05-29 12:36:30');
insert into `test` (`id`, `name`, `company`, `age`, `create_time`) values('10','李六','alibaba','28','2020-05-29 12:36:31');
insert into `test` (`id`, `name`, `company`, `age`, `create_time`) values('11','张三丰','jd','108','2020-05-29 12:36:31');
insert into `test` (`id`, `name`, `company`, `age`, `create_time`) values('12','张三丰','jd','108','2020-05-29 12:36:31');
insert into `test` (`id`, `name`, `company`, `age`, `create_time`) values('13','张三丰','jd','108','2020-05-29 12:36:31');
insert into `test` (`id`, `name`, `company`, `age`, `create_time`) values('14','张一1','huawei','18','2020-05-29 12:36:11');
insert into `test` (`id`, `name`, `company`, `age`, `create_time`) values('15','张二1','huawei','19','2020-05-29 12:36:13');
insert into `test` (`id`, `name`, `company`, `age`, `create_time`) values('16','张三1','huawei','20','2020-05-29 12:36:15');
insert into `test` (`id`, `name`, `company`, `age`, `create_time`) values('17','张四1','huawei','22','2020-05-29 12:36:16');
insert into `test` (`id`, `name`, `company`, `age`, `create_time`) values('18','李一1','baidu','22','2020-05-29 12:36:18');
insert into `test` (`id`, `name`, `company`, `age`, `create_time`) values('19','李二1','huawei','22','2020-05-29 12:36:24');
insert into `test` (`id`, `name`, `company`, `age`, `create_time`) values('20','李三1','baidu','22','2020-05-29 12:36:25');
insert into `test` (`id`, `name`, `company`, `age`, `create_time`) values('21','李四1','baidu','26','2020-05-29 12:36:28');
insert into `test` (`id`, `name`, `company`, `age`, `create_time`) values('22','李五1','baidu','27','2020-05-29 12:36:30');
insert into `test` (`id`, `name`, `company`, `age`, `create_time`) values('23','李六1','alibaba','28','2020-05-29 12:36:31');
insert into `test` (`id`, `name`, `company`, `age`, `create_time`) values('24','张三丰1','jd','108','2020-05-29 12:36:31');
insert into `test` (`id`, `name`, `company`, `age`, `create_time`) values('25','张三丰1','jd','108','2020-05-29 12:36:31');
insert into `test` (`id`, `name`, `company`, `age`, `create_time`) values('26','张三丰1','jd','108','2020-05-29 12:36:31');
insert into `test` (`id`, `name`, `company`, `age`, `create_time`) values('28','张二1','huawei11','19','2020-05-29 12:36:13');
insert into `test` (`id`, `name`, `company`, `age`, `create_time`) values('29','张三1','huawei11','20','2020-05-29 12:36:15');
insert into `test` (`id`, `name`, `company`, `age`, `create_time`) values('30','张四1','huawei11','22','2020-05-29 12:36:16');
insert into `test` (`id`, `name`, `company`, `age`, `create_time`) values('31','李一1','baidu11','22','2020-05-29 12:36:18');
insert into `test` (`id`, `name`, `company`, `age`, `create_time`) values('32','李二1','huawei11','22','2020-05-29 12:36:24');
insert into `test` (`id`, `name`, `company`, `age`, `create_time`) values('33','李三1','baidu11','22','2020-05-29 12:36:25');
insert into `test` (`id`, `name`, `company`, `age`, `create_time`) values('34','李四1','baidu11','26','2020-05-29 12:36:28');
insert into `test` (`id`, `name`, `company`, `age`, `create_time`) values('35','李五1','baidu11','27','2020-05-29 12:36:30');
insert into `test` (`id`, `name`, `company`, `age`, `create_time`) values('36','李六1','alibaba11','28','2020-05-29 12:36:31');
insert into `test` (`id`, `name`, `company`, `age`, `create_time`) values('37','张三丰1','jd11','108','2020-05-29 12:36:31');
insert into `test` (`id`, `name`, `company`, `age`, `create_time`) values('38','张三丰1','jd11','108','2020-05-29 12:36:31');
insert into `test` (`id`, `name`, `company`, `age`, `create_time`) values('39','张三丰1','jd11','108','2020-05-29 12:36:31');
insert into `test` (`id`, `name`, `company`, `age`, `create_time`) values('40','张一9','huawei11','18','2020-05-29 12:36:11');
insert into `test` (`id`, `name`, `company`, `age`, `create_time`) values('41','张二9','huawei11','19','2020-05-29 12:36:13');
insert into `test` (`id`, `name`, `company`, `age`, `create_time`) values('42','张三9','huawei11','20','2020-05-29 12:36:15');
insert into `test` (`id`, `name`, `company`, `age`, `create_time`) values('43','张四9','huawei11','22','2020-05-29 12:36:16');
insert into `test` (`id`, `name`, `company`, `age`, `create_time`) values('44','李一9','baidu11','22','2020-05-29 12:36:18');
insert into `test` (`id`, `name`, `company`, `age`, `create_time`) values('45','李二9','huawei11','22','2020-05-29 12:36:24');
insert into `test` (`id`, `name`, `company`, `age`, `create_time`) values('46','李三9','baidu11','22','2020-05-29 12:36:25');
insert into `test` (`id`, `name`, `company`, `age`, `create_time`) values('47','李四9','baidu11','26','2020-05-29 12:36:28');
insert into `test` (`id`, `name`, `company`, `age`, `create_time`) values('48','李五9','baidu11','27','2020-05-29 12:36:30');
insert into `test` (`id`, `name`, `company`, `age`, `create_time`) values('49','李六9','alibaba11','28','2020-05-29 12:36:31');
insert into `test` (`id`, `name`, `company`, `age`, `create_time`) values('50','张一9','huawei11','18','2020-05-29 12:36:11');
insert into `test` (`id`, `name`, `company`, `age`, `create_time`) values('51','张二9','huawei11','19','2020-05-29 12:36:13');
insert into `test` (`id`, `name`, `company`, `age`, `create_time`) values('52','张三9','huawei11','20','2020-05-29 12:36:15');
insert into `test` (`id`, `name`, `company`, `age`, `create_time`) values('53','张四9','huawei11','22','2020-05-29 12:36:16');
insert into `test` (`id`, `name`, `company`, `age`, `create_time`) values('54','李一9','baidu11','22','2020-05-29 12:36:18');
insert into `test` (`id`, `name`, `company`, `age`, `create_time`) values('55','李二9','huawei11','22','2020-05-29 12:36:24');
insert into `test` (`id`, `name`, `company`, `age`, `create_time`) values('56','李三9','baidu11','22','2020-05-29 12:36:25');
insert into `test` (`id`, `name`, `company`, `age`, `create_time`) values('57','李四9','baidu11','26','2020-05-29 12:36:28');
insert into `test` (`id`, `name`, `company`, `age`, `create_time`) values('58','李五9','baidu11','27','2020-05-29 12:36:30');
insert into `test` (`id`, `name`, `company`, `age`, `create_time`) values('59','李六9','alibaba11','28','2020-05-29 12:36:31');
insert into `test` (`id`, `name`, `company`, `age`, `create_time`) values('60','张一9','huawei11','18','2020-05-29 12:36:11');
insert into `test` (`id`, `name`, `company`, `age`, `create_time`) values('61','张二9','huawei11','19','2020-05-29 12:36:13');
insert into `test` (`id`, `name`, `company`, `age`, `create_time`) values('62','张三9','huawei11','20','2020-05-29 12:36:15');
insert into `test` (`id`, `name`, `company`, `age`, `create_time`) values('63','张四9','huawei11','22','2020-05-29 12:36:16');
insert into `test` (`id`, `name`, `company`, `age`, `create_time`) values('64','李一9','baidu11','22','2020-05-29 12:36:18');
insert into `test` (`id`, `name`, `company`, `age`, `create_time`) values('65','李二9','huawei11','22','2020-05-29 12:36:24');
insert into `test` (`id`, `name`, `company`, `age`, `create_time`) values('66','李三9','baidu11','22','2020-05-29 12:36:25');
insert into `test` (`id`, `name`, `company`, `age`, `create_time`) values('67','李四9','baidu11','26','2020-05-29 12:36:28');
insert into `test` (`id`, `name`, `company`, `age`, `create_time`) values('68','李五9','baidu11','27','2020-05-29 12:36:30');
insert into `test` (`id`, `name`, `company`, `age`, `create_time`) values('69','李六9','alibaba11','28','2020-05-29 12:36:31');
insert into `test` (`id`, `name`, `company`, `age`, `create_time`) values('70','张一9','huawei11','18','2020-05-29 12:36:11');
insert into `test` (`id`, `name`, `company`, `age`, `create_time`) values('71','张二9','huawei11','19','2020-05-29 12:36:13');
insert into `test` (`id`, `name`, `company`, `age`, `create_time`) values('72','张三9','huawei11','20','2020-05-29 12:36:15');
insert into `test` (`id`, `name`, `company`, `age`, `create_time`) values('73','张四9','huawei11','22','2020-05-29 12:36:16');
insert into `test` (`id`, `name`, `company`, `age`, `create_time`) values('74','李一9','baidu11','22','2020-05-29 12:36:18');
insert into `test` (`id`, `name`, `company`, `age`, `create_time`) values('75','李二9','huawei11','22','2020-05-29 12:36:24');
insert into `test` (`id`, `name`, `company`, `age`, `create_time`) values('76','李三9','baidu11','22','2020-05-29 12:36:25');
insert into `test` (`id`, `name`, `company`, `age`, `create_time`) values('77','李四9','baidu11','26','2020-05-29 12:36:28');
insert into `test` (`id`, `name`, `company`, `age`, `create_time`) values('78','李五9','baidu11','27','2020-05-29 12:36:30');
insert into `test` (`id`, `name`, `company`, `age`, `create_time`) values('79','李六9','alibaba11','28','2020-05-29 12:36:31');
insert into `test` (`id`, `name`, `company`, `age`, `create_time`) values('80','张一科','huawei11','18','2020-05-29 12:36:11');
insert into `test` (`id`, `name`, `company`, `age`, `create_time`) values('81','张二科','huawei11','19','2020-05-29 12:36:13');
insert into `test` (`id`, `name`, `company`, `age`, `create_time`) values('82','张三科','huawei11','20','2020-05-29 12:36:15');
insert into `test` (`id`, `name`, `company`, `age`, `create_time`) values('83','张四科','huawei11','22','2020-05-29 12:36:16');
insert into `test` (`id`, `name`, `company`, `age`, `create_time`) values('84','李一科','baidu11','22','2020-05-29 12:36:18');
insert into `test` (`id`, `name`, `company`, `age`, `create_time`) values('85','李二科','huawei11','22','2020-05-29 12:36:24');
insert into `test` (`id`, `name`, `company`, `age`, `create_time`) values('86','李三科','baidu11','22','2020-05-29 12:36:25');
insert into `test` (`id`, `name`, `company`, `age`, `create_time`) values('87','李四科','baidu11','26','2020-05-29 12:36:28');
insert into `test` (`id`, `name`, `company`, `age`, `create_time`) values('88','李五科','baidu11','27','2020-05-29 12:36:30');
insert into `test` (`id`, `name`, `company`, `age`, `create_time`) values('89','李六科','alibaba11','28','2020-05-29 12:36:31');
insert into `test` (`id`, `name`, `company`, `age`, `create_time`) values('90','张一科','huawei11','18','2020-05-29 12:36:11');
insert into `test` (`id`, `name`, `company`, `age`, `create_time`) values('91','张二科','huawei11','19','2020-05-29 12:36:13');
insert into `test` (`id`, `name`, `company`, `age`, `create_time`) values('92','张三科','huawei11','20','2020-05-29 12:36:15');
insert into `test` (`id`, `name`, `company`, `age`, `create_time`) values('93','张四科','huawei11','22','2020-05-29 12:36:16');
insert into `test` (`id`, `name`, `company`, `age`, `create_time`) values('94','李一科','baidu11','22','2020-05-29 12:36:18');
insert into `test` (`id`, `name`, `company`, `age`, `create_time`) values('95','李二科','huawei11','22','2020-05-29 12:36:24');
insert into `test` (`id`, `name`, `company`, `age`, `create_time`) values('96','李三科','baidu11','22','2020-05-29 12:36:25');
insert into `test` (`id`, `name`, `company`, `age`, `create_time`) values('97','李四科','baidu11','26','2020-05-29 12:36:28');
insert into `test` (`id`, `name`, `company`, `age`, `create_time`) values('98','李五科','baidu11','27','2020-05-29 12:36:30');
insert into `test` (`id`, `name`, `company`, `age`, `create_time`) values('99','李六科','alibaba11','28','2020-05-29 12:36:31');
insert into `test` (`id`, `name`, `company`, `age`, `create_time`) values('100','张一科','huawei11','18','2020-05-29 12:36:11');
insert into `test` (`id`, `name`, `company`, `age`, `create_time`) values('101','张二科','huawei11','19','2020-05-29 12:36:13');
insert into `test` (`id`, `name`, `company`, `age`, `create_time`) values('102','张三科','huawei11','20','2020-05-29 12:36:15');
insert into `test` (`id`, `name`, `company`, `age`, `create_time`) values('103','张四科','huawei11','22','2020-05-29 12:36:16');
insert into `test` (`id`, `name`, `company`, `age`, `create_time`) values('104','李一科','baidu11','22','2020-05-29 12:36:18');
insert into `test` (`id`, `name`, `company`, `age`, `create_time`) values('105','李二科','huawei11','22','2020-05-29 12:36:24');
insert into `test` (`id`, `name`, `company`, `age`, `create_time`) values('106','李三科','baidu11','22','2020-05-29 12:36:25');
insert into `test` (`id`, `name`, `company`, `age`, `create_time`) values('107','李四科','baidu11','26','2020-05-29 12:36:28');
insert into `test` (`id`, `name`, `company`, `age`, `create_time`) values('108','李五科','baidu11','27','2020-05-29 12:36:30');
insert into `test` (`id`, `name`, `company`, `age`, `create_time`) values('109','李六科','alibaba11','28','2020-05-29 12:36:31');
insert into `test` (`id`, `name`, `company`, `age`, `create_time`) values('111','张二科','huawei11','19','2020-05-29 12:36:13');
insert into `test` (`id`, `name`, `company`, `age`, `create_time`) values('112','张三科','huawei11','20','2020-05-29 12:36:15');
insert into `test` (`id`, `name`, `company`, `age`, `create_time`) values('113','张四科','huawei11','22','2020-05-29 12:36:16');
insert into `test` (`id`, `name`, `company`, `age`, `create_time`) values('114','李一科','baidu11','22','2020-05-29 12:36:18');
insert into `test` (`id`, `name`, `company`, `age`, `create_time`) values('115','李二科','huawei11','22','2020-05-29 12:36:24');
insert into `test` (`id`, `name`, `company`, `age`, `create_time`) values('116','李三科','baidu11','22','2020-05-29 12:36:25');
insert into `test` (`id`, `name`, `company`, `age`, `create_time`) values('117','李四科','baidu11','26','2020-05-29 12:36:28');
insert into `test` (`id`, `name`, `company`, `age`, `create_time`) values('118','李五科','baidu11','27','2020-05-29 12:36:30');
insert into `test` (`id`, `name`, `company`, `age`, `create_time`) values('119','李六科','alibaba11','28','2020-05-29 12:36:31');
insert into `test` (`id`, `name`, `company`, `age`, `create_time`) values('120','张丹峰','tx','36','2020-05-29 22:36:31');
insert into `test` (`id`, `name`, `company`, `age`, `create_time`) values('121','test','tttt','44','2020-05-30 06:19:12');
insert into `test` (`id`, `name`, `company`, `age`, `create_time`) values('122','张一5','bbaidu','30','2020-05-30 09:20:08');
然后执行explain执行计划
EXPLAIN SELECT * FROM teacher
每列的含义如下**后面的字段及类型说明全部参考官网,并结合自己弱弱的英文进行翻译而来,可以算的上是最全的整理了,关注孤狼,和孤狼一起学习进步**
列 | 英文释义 | 中文翻译 |
---|---|---|
id | The SELECT identifier | id标识符 |
select_type | The SELECT type | 查询类型 |
table | The table for the output row | 输出行的表名 |
partitions | The matching partitions | 匹配的分区 |
type | The join type | 关联类型 |
possible_keys | The possible indexes to choose | 可能选择的索引 |
key | The index actually chosen | 最终选择使用的索引 |
key_len | The length of the chosen key | 选中的索引的长度 |
ref | The columns compared to the index | 与索引比较的列 |
rows | Estimate of rows to be examined | 预估需要扫描的行数 |
filtered | Percentage of rows filtered by table condition | 根据条件实际过滤数据百分比 |
Extra | Additional information | 附加信息 |
如果id都相同,那么sql先执行的是按顺序从上到下执行,如果id不同,那么是从大到小执行,优先从大到小,也就是按照8字原则:先大后小,从上到下。当select_type出现
如下面的截图中,表示MySQL最先执行的最后面的一句(从大到小),然后从第1条开始执行,直到全部执行完毕(从上到下)。
SELECT的类型,可以是下表中显示的任何类型。JSON名称(如适用)也会显示在表中:
select_type | JSON名称 | 英文释义 | 中文翻译 |
---|---|---|---|
SIMPLE | None | Simple SELECT (not using UNION or subqueries) | 没有用到union或者子查询的简单查询语句 |
PRIMARY | None | Outermost SELECT | 最外层的查询,即:主查询 |
UNION | None | Second or later SELECT statement in a UNION | union查询中第二个(含)之后的查询语句 |
DEPENDENT UNION | dependent (true) | Second or later SELECT statement in a UNION, dependent on outer query | union查询中第二个(含)之后的查询且依赖于外部查询 |
UNION RESULT | union_result | Result of a UNION | 联合查询的结果(此时id为Null) |
SUBQUERY | None | First SELECT in subquery | 子查询中的第一个查询 |
DEPENDENT SUBQUERY | dependent (true) | First SELECT in subquery, dependent on outer query | 子查询中的第一个查询且依赖于外部查询 |
DERIVED | None | Derived table | 派生表(如:select * from (select * from t) a查询语句中a表就是派生表) |
MATERIALIZED | materialized_from_subquery | Materialized subquery | 物化子查询 |
UNCACHEABLE SUBQUERY | cacheable (false) | A subquery for which the result cannot be cached and must be re-evaluated for each row of the outer query | 子查询的结果不能被缓存,只能被外部查询重新一行行匹配 |
UNCACHEABLE UNION | cacheable (false) | The second or later select in a UNION that belongs to an uncacheable subquery (see UNCACHEABLE SUBQUERY) | union语句中第二个(含)以后的查询是一个UNCACHEABLE SUBQUERY查询 |
当前行输出的表名。
描述了实际查询是如何连接表的,下面我们依据查询效率最优到最差开始逐个介绍举例:(需要注意的是,测试的时候数据不要太少了,如果数据太少可能不会出现预期效果,因为有时候数据过少MySQL就不会使用过多优化手段,转而会直接全表扫描)
系统表里面只有一行记录,这个是const类型中的特殊情况。
EXPLAIN SELECT * FROM mysql.`time_zone` -- 这条记录是我自己写进去测试的
表最多有一个匹配行,在查询开始时读取。因为只有一行,所以这一行中列的值可以被优化器的其他部分视为常量。const表非常快,因为它们只被读取一次。
const用于将主键或唯一索引的所有部分与常量值进行比较。const适用于如下查询:
SELECT * FROM tbl_name WHERE primary_key=1;
SELECT * FROM tbl_name WHERE primary_key_part1=1 AND primary_key_part2=2;
举例1:
EXPLAIN SELECT * FROM USER WHERE id=1;
ALTER TABLE USER DROP PRIMARY KEY; -- 删除原先主键索引
ALTER TABLE USER ADD PRIMARY KEY (id,NAME);-- 新建联合主键索引
EXPLAIN SELECT * FROM USER WHERE id=1 AND NAME='张一';
对于前一个表中的每个组合,从这个表中读取一行。除了system和const类型之外,这是最好的连接类型。当使用索引的所有部分并且索引是主键或唯一非空索引时,将使用该类型。
eq_ref可以用于使用=操作符进行比较的索引列。比较值可以是常量,也可以是使用在该表之前读取的表中的列的表达式。
简单的说:就是两张表通过其中一张表的主键或者唯一非空索引进行关联时,查询结果是一对一的关系。
eq_ref适用于如下查询:
SELECT * FROM ref_table,other_table
WHERE ref_table.key_column=other_table.column;
SELECT * FROM ref_table,other_table
WHERE ref_table.key_column_part1=other_table.column
AND ref_table.key_column_part2=1;
举例1:
EXPLAIN SELECT * FROM USER u,user_detail d WHERE u.detail_id=d.id
ALTER TABLE user_job DROP PRIMARY KEY;-- 删除主键单列索引
ALTER TABLE user_job ADD PRIMARY KEY id_name_index(id,job_name);-- 添加联合主键索引
EXPLAIN SELECT * FROM `user` u,user_job j WHERE u.job_id=j.id AND job_name='CEO';
对于前一个表中的每个行组合,从这个表中读取具有匹配索引值的所有行。如果连接只使用键的最左端前缀,或者如果键不是主键或惟一索引(换句话说,如果连接不能根据键值选择单个行),则使用ref。如果使用的键只匹配几行,这是一种很好的连接类型。
这个和eq_ref最大的区别是ref一般用于普通索引的场景下,而eq_ref是用于主键或者唯一非空索引
ref适用于如下三种类型查询:
SELECT * FROM ref_table WHERE key_column=expr;
SELECT * FROM ref_table,other_table
WHERE ref_table.key_column=other_table.column;
SELECT * FROM ref_table,other_table
WHERE ref_table.key_column_part1=other_table.column
AND ref_table.key_column_part2=1;
举例1:
ALTER TABLE user_detail DROP PRIMARY KEY;-- 删除主键索引
ALTER TABLE user_detail ADD INDEX id_index(id);-- 添加一个普通索引
EXPLAIN SELECT * FROM user_detail WHERE id=1
EXPLAIN SELECT * FROM USER u,user_detail d WHERE u.detail_id=d.id;
ALTER TABLE user_job DROP PRIMARY KEY;-- 删除联合主键索引
ALTER TABLE user_job ADD INDEX id_name_index(id,job_name);-- 添加普通的联合主键索引
EXPLAIN SELECT * FROM `user` u,user_job j WHERE u.job_id=j.id AND job_name='CEO';
这个比较简单,用到了全文索引就会出现,就不做演示了,感兴趣的可以点击这里,了解全文索引
这个连接类型类似于ref,但是多了一个对空值的搜索条件。这种连接类型优化最常用于解析子查询。适用于如下查询:
SELECT * FROM ref_table WHERE key_column=expr OR key_column IS NULL;
举例:
ALTER TABLE user_detail MODIFY COLUMN id INT(3) DEFAULT NULL;
EXPLAIN SELECT * FROM user_detail WHERE `id`='111' OR `id` IS NULL;
注意,这个例子中因为id是整型,本人这边因为反复修改索引,导致id列已经有了默认值为0,所以MySQL知道这一列没有null值,直接查询是不会出现这种类型的,故而才需要改为默认值为null
索引合并访问方法检索具有多个范围扫描的行,并将其结果合并为一个。此访问方法仅合并来自单个表的索引扫描,不能跨多个表扫描。合并可以生成其底层扫描的联合、交叉或交叉的联合。
想要详细了解索引合并的概念,请点击这里。
下面几种情况可能会用到索引合并:
SELECT * FROM tbl_name WHERE key1 = 10 OR key2 = 20;
SELECT * FROM tbl_name
WHERE (key1 = 10 OR key2 = 20) AND non_key = 30;
SELECT * FROM t1, t2
WHERE (t1.key1 IN (1,2) OR t1.key2 LIKE 'value%')
AND t2.key1 = t1.some_col;
SELECT * FROM t1, t2
WHERE t1.key1 = 1
AND (t2.key1 = t1.some_col OR t2.key2 = t1.some_col2);
举例1(注意test表有一个主键索引和一个普通索引):
EXPLAIN SELECT * FROM test WHERE id = 1 OR NAME='张三丰'
这里之所以会单独准备一张test表是因为其他表数据都太少了,数据少的时候全表扫描有时候会比使用其他优化措施效率更高
举例2
EXPLAIN SELECT * FROM test WHERE (id = 1 OR NAME='张三丰') AND company='huawei';
这个类型替换了表单的子查询中的一些eq_ref,一般用于子查询,而且子查询只返回主键或者唯一索引:
value IN (SELECT primary_key FROM single_table WHERE some_expr)
unique_subquery只是一个索引查找函数,它完全取代了子查询以提高效率。
举例(test表和user表中id均为主键):
EXPLAIN SELECT * FROM `user` u WHERE id IN (SELECT id FROM `test` t) OR `name`='张一'
这里不知道各位会不会奇怪,为什么查询条件要加一个or,如果把or去掉呢?去掉之后的执行计划如下图:
有一个明显的区别,加了or先执行的子查询(图一中t表的查询id为2,所以先执行),而不加or,先查询的是u表(图2中id都是1,从上往下执行),所以说我们加一个or只是为了确保MySQL会先执行子查询,这样才会出现unique_subquery。
题外话:很多人查询的时候用子查询以为MySQL会先执行子查询,实际上大部分情况都是不会的,都是先执行的外层查询,再一条条记录去和子查询匹配,这也就是为什么很多人建议不要用子查询的原因,当然,这也不是绝对的,有的时候子查询的效率也会更高,所以具体的还是要视业务数据来具体分析
这种类型和unique_subquery非常类似,唯一不同的就是子查询中返回的不是主键或者唯一索引:
value IN (SELECT key_column FROM single_table WHERE some_expr)
举例(确保test表中name字段有一个普通索引):
EXPLAIN SELECT * FROM `user` u WHERE `name` IN (SELECT `name` FROM `test` t) OR `name`='张一';
使用索引去检索范围内的行,输出行中的键列指示使用哪个索引。基本上是用到了以下操作符: !=, <>, >, >=, <, <=, IS NULL, <=>, BETWEEN, LIKE, or IN()。
注意:注意,这里的第一个操作符和下面的第一个语法样例,官网写的是等于,个人认为应该是不等于,如果使用=,那么key_cloumn是主键和唯一索引则是eq_ref类型,普通索引则是ref类型,没有索引则是ALL
题外话:<==>操作符相当于判断两个值是否相等,不同的是这个是可以判断null值的,即cloumn is null 等价于 column<=>null。
SELECT * FROM tbl_name
WHERE key_column != 10;
SELECT * FROM tbl_name
WHERE key_column BETWEEN 10 and 20;
SELECT * FROM tbl_name
WHERE key_column IN (10,20,30);
SELECT * FROM tbl_name
WHERE key_part1 = 10 AND key_part2 IN (10,20,30);
举例(其他例子就不举了,这个相对比较简单了):
EXPLAIN SELECT id,NAME FROM `test` WHERE id !=1;
即:Full Index Scan(全索引扫描)。当查询只使用属于单个索引的列时,MySQL可以使用这种连接类型。这种类型和ALL是差不多的,ALL是扫描全表,index是扫描全索引。index会发生在以下两种情况:
举例1(使用覆盖索引):
EXPLAIN SELECT id,NAME FROM `test`;
举例2(按索引顺序读取):
EXPLAIN SELECT id FROM `test`;
全表扫描,最差的一种查询。不带where条件或者where条件没有使用到任何索引的情况。
不需要用到表就可以返回结果。
EXPLAIN SELECT NOW();
扩展信息列,这一列可以展示很多信息,而且一次查询可能会同时出现多个,官网列举了几十种,在这里就不一一列举,只举一些非常常用的又比较重要的信息。
Extra中的信息和上面介绍的select_type是不同的两种信息,不能混为一谈。
接下来的介绍会涉及到:覆盖索引,回表,索引下推等概念,如果想详细了解这些概念的,可以点击这里。
MySQL会进行一个额外的遍历来排序,也就是说这种情况的排序字段没有用到索引(这种需要尽可能优化)。
举例:(下面这个例子中name不管有没有索引都是filesort,因为用到了select *,后面的例子会介绍不用*会有什么区别)
EXPLAIN SELECT * FROM `test` ORDER BY `name`; -- test表有一个id主键索引和name普通索引
表示用到了覆盖索引。
举例:(下面这个例子用到了覆盖索引,不需要回表,所以可以使用name这个普通索引来排序,而如果需要回表,就不能直接用name的索引来排序了,就会变成上面的filesort)
EXPLAIN SELECT `id`,`name` FROM `test` ORDER BY `name`;
表示用到了索引下推(需要确保开启了索引下推)。
举例:
EXPLAIN SELECT * FROM `test` WHERE `name` LIKE '张一%' AND `name` LIKE '%1%';
上面例子中,name的第二个条件肯定用不到索引,正常是第一个条件筛选出数据后就会返回server层进行第二个条件过滤,而开启了索引下推,就会继续进行第二个条件过滤之后再返回(这种如果第二个条件可以过滤大量数据的情况下,索引下推可以极大提高性能)
表示用到了Multi-Range Read优化(需要确保开启了MRR)。
EXPLAIN SELECT * FROM `test` WHERE `name` LIKE '张%';
表示索引层能完成过滤,需要返回server进行再次过滤筛选(上面的MRR例子中就会同时出现Using where)。
MySQL需要创建一个临时表来保存结果。如果查询包含GROUP BY和ORDER BY,通常会发生这种情况(这种需要尽可能优化)。。
举例:
EXPLAIN SELECT DISTINCT(`company`) FROM `test` WHERE `name` LIKE '张一%';
EXPLAIN SELECT `company`,COUNT(*) FROM `test` GROUP BY `company`;
关于Extra暂时就列举这些,这些相对是比较常见的信息,如果你认为还有其他比较重要的类型,可以留言或者私信给我,我这边更新加上,最好要带上对应的sql语句哦。
下一篇,我将为大家介绍【MySQL中的事务和锁,以及MVCC等相关知识】,请关注我,和孤狼一起学习进步。