explain執行計劃分析
前言
上一篇爲大家介紹了MySQL中索引的存儲結構已經索引類型和什麼時候會用到索引等相關知識,想了解詳細,請點擊這裏。這一篇將爲大家分享如何用EXPLAIN關鍵字來分析sql語句的執行方式並預估效率,從而進行鍼對性的優化。
初識explain
有時候我們寫好了一條語句,想確認是不是會按我們想要的順序或者有沒有用到我們想讓他用到的索引,這時候就可以用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
返回結果:
explain返回結果說明
每列的含義如下**後面的字段及類型說明全部參考官網,並結合自己弱弱的英文進行翻譯而來,可以算的上是最全的整理了,關注孤狼,和孤狼一起學習進步**
列 | 英文釋義 | 中文翻譯 |
---|---|---|
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
如果id都相同,那麼sql先執行的是按順序從上到下執行,如果id不同,那麼是從大到小執行,優先從大到小,也就是按照8字原則:先大後小,從上到下。當select_type出現 <unionM,N> 的時候id會顯示爲null。
如下面的截圖中,表示MySQL最先執行的最後面的一句(從大到小),然後從第1條開始執行,直到全部執行完畢(從上到下)。
select_type
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查詢 |
table
當前行輸出的表名。
- <unionM,N>: 表示當前行的結果是id爲M和N的union的結果。
- <\derivedN>:表示當前行的表是由id爲N的查詢結果的派生表。
- <\subqueryN>: 表示當前行的結果是id爲N的子查詢結果。
type
描述了實際查詢是如何連接表的,下面我們依據查詢效率最優到最差開始逐個介紹舉例:(需要注意的是,測試的時候數據不要太少了,如果數據太少可能不會出現預期效果,因爲有時候數據過少MySQL就不會使用過多優化手段,轉而會直接全表掃描)
system類型
系統表裏面只有一行記錄,這個是const類型中的特殊情況。
EXPLAIN SELECT * FROM mysql.`time_zone` -- 這條記錄是我自己寫進去測試的
const 類型
表最多有一個匹配行,在查詢開始時讀取。因爲只有一行,所以這一行中列的值可以被優化器的其他部分視爲常量。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;
舉例2::
ALTER TABLE USER DROP PRIMARY KEY; -- 刪除原先主鍵索引
ALTER TABLE USER ADD PRIMARY KEY (id,NAME);-- 新建聯合主鍵索引
EXPLAIN SELECT * FROM USER WHERE id=1 AND NAME='張一';
eq_ref
對於前一個表中的每個組合,從這個表中讀取一行。除了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
舉例2:
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
對於前一個表中的每個行組合,從這個表中讀取具有匹配索引值的所有行。如果連接只使用鍵的最左端前綴,或者如果鍵不是主鍵或惟一索引(換句話說,如果連接不能根據鍵值選擇單個行),則使用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
舉例2:
EXPLAIN SELECT * FROM USER u,user_detail d WHERE u.detail_id=d.id;
舉例3:
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';
fulltext
這個比較簡單,用到了全文索引就會出現,就不做演示了,感興趣的可以點擊這裏,瞭解全文索引
ref_or_null
這個連接類型類似於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
index_merge
索引合併訪問方法檢索具有多個範圍掃描的行,並將其結果合併爲一個。此訪問方法僅合併來自單個表的索引掃描,不能跨多個表掃描。合併可以生成其底層掃描的聯合、交叉或交叉的聯合。
想要詳細瞭解索引合併的概念,請點擊這裏。
下面幾種情況可能會用到索引合併:
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';
unique_subquery
這個類型替換了表單的子查詢中的一些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會先執行子查詢,實際上大部分情況都是不會的,都是先執行的外層查詢,再一條條記錄去和子查詢匹配,這也就是爲什麼很多人建議不要用子查詢的原因,當然,這也不是絕對的,有的時候子查詢的效率也會更高,所以具體的還是要視業務數據來具體分析
index_subquery
這種類型和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`='張一';
range
使用索引去檢索範圍內的行,輸出行中的鍵列指示使用哪個索引。基本上是用到了以下操作符: !=, <>, >, >=, <, <=, 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;
index
即:Full Index Scan(全索引掃描)。當查詢只使用屬於單個索引的列時,MySQL可以使用這種連接類型。這種類型和ALL是差不多的,ALL是掃描全表,index是掃描全索引。index會發生在以下兩種情況:
- 使用到了覆蓋索引
- 按照索引的順序來進行讀取數據
舉例1(使用覆蓋索引):
EXPLAIN SELECT id,NAME FROM `test`;
舉例2(按索引順序讀取):
EXPLAIN SELECT id FROM `test`;
ALL
全表掃描,最差的一種查詢。不帶where條件或者where條件沒有使用到任何索引的情況。
NULL
不需要用到表就可以返回結果。
EXPLAIN SELECT NOW();
Extra
擴展信息列,這一列可以展示很多信息,而且一次查詢可能會同時出現多個,官網列舉了幾十種,在這裏就不一一列舉,只舉一些非常常用的又比較重要的信息。
Extra中的信息和上面介紹的select_type是不同的兩種信息,不能混爲一談。
接下來的介紹會涉及到:覆蓋索引,回表,索引下推等概念,如果想詳細瞭解這些概念的,可以點擊這裏。
Using filesort
MySQL會進行一個額外的遍歷來排序,也就是說這種情況的排序字段沒有用到索引(這種需要儘可能優化)。
舉例:(下面這個例子中name不管有沒有索引都是filesort,因爲用到了select *,後面的例子會介紹不用*會有什麼區別)
EXPLAIN SELECT * FROM `test` ORDER BY `name`; -- test表有一個id主鍵索引和name普通索引
Using index
表示用到了覆蓋索引。
舉例:(下面這個例子用到了覆蓋索引,不需要回表,所以可以使用name這個普通索引來排序,而如果需要回表,就不能直接用name的索引來排序了,就會變成上面的filesort)
EXPLAIN SELECT `id`,`name` FROM `test` ORDER BY `name`;
Using index condition
表示用到了索引下推(需要確保開啓了索引下推)。
舉例:
EXPLAIN SELECT * FROM `test` WHERE `name` LIKE '張一%' AND `name` LIKE '%1%';
上面例子中,name的第二個條件肯定用不到索引,正常是第一個條件篩選出數據後就會返回server層進行第二個條件過濾,而開啓了索引下推,就會繼續進行第二個條件過濾之後再返回(這種如果第二個條件可以過濾大量數據的情況下,索引下推可以極大提高性能)
Using MRR
表示用到了Multi-Range Read優化(需要確保開啓了MRR)。
EXPLAIN SELECT * FROM `test` WHERE `name` LIKE '張%';
Using where
表示索引層能完成過濾,需要返回server進行再次過濾篩選(上面的MRR例子中就會同時出現Using where)。
Using temporary
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等相關知識】,請關注我,和孤狼一起學習進步。