文章目錄
數據結構-索引-實驗1:EXPLAIN分析SQL的執行計劃
一、實驗目的及要求
1、 理解EXPLAIN的相關概念;
2、 掌握EXPLAIN的使用;
二、實驗環境及相關情況(包含使用軟件、實驗設備、主要儀器及材料等)
1、實驗設備:
(1)微型計算機:i7處理器、2G內存
2、軟件系統:
(1)VMware Workstation 15 Player:虛擬機,用於安裝Windows 7操作系統。在虛擬機上安裝Windows 7,然後再安裝MySQL-8.0.13-winx64;
(2)Windows 7操作系統:
(3)MySQL-8.0.13-winx64:
(4)Navicat Premium 12:數據庫管理工具。
三、實驗內容
1、 數據準備。
2、EXPLAIN結果列詳解
四、實驗步驟及結果(包含簡要的實驗步驟流程、結論陳述,可附頁)
(一)數據準備
1、user
(1)表結構
-- 時間: 0s
SET NAMES utf8mb4;
-- 時間: 0s
SET FOREIGN_KEY_CHECKS = 0;
-- 時間: 0.001s
DROP TABLE IF EXISTS `user`;
CREATE TABLE `user` (
`id` int(11) NOT NULL AUTO_INCREMENT COMMENT '主鍵',
`name` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '姓名',
`gender` char(1) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '性別:F-女;M-男',
`age` int(3) NULL DEFAULT NULL COMMENT '年齡',
`email` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '郵箱',
`message` text CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL COMMENT '個人信息',
`a` int(11) NULL DEFAULT NULL,
`b` int(11) NULL DEFAULT NULL,
`c` int(11) NULL DEFAULT NULL,
`d` int(11) NULL DEFAULT NULL,
`state` int(1) NOT NULL DEFAULT 0 COMMENT '狀態:0有效1無效',
PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci ROW_FORMAT = Dynamic;
-- 時間: 0s
SET FOREIGN_KEY_CHECKS = 1;
(2)數據
第一,插入基礎數據
-- 時間: 0.036s
INSERT INTO `test`.`user`(`id`, `name`, `gender`, `age`, `email`, `message`, `a`, `b`, `c`, `d`,`state`) VALUES (1, '1', 'F', 13, '[email protected]', '在關係數據庫中,索引是一種單獨的、物理的對數據庫表中一列或多列的值進行排序的一種存儲結構,它是某個表中一列或若干列值的集合和相應的指向表中物理標識這些值的數據頁的邏輯指針清單。索引的作用相當於圖書的目錄,可以根據目錄中的頁碼快速找到所需的內容。\r\n索引提供指向存儲在表的指定列中的數據值的指針,然後根據您指定的排序順序對這些指針排序。數據庫使用索引以找到特定值,然後順指針找到包含該值的行。這樣可以使對應於表的SQL語句執行得更快,可快速訪問數據庫表中的特定信息。\r\n當表中有大量記錄時,若要對錶進行查詢,第一種搜索信息方式是全表搜索,是將所有記錄一一取出,和查詢條件進行一一對比,然後返回滿足條件的記錄,這樣做會消耗大量數據庫系統時間,並造成大量磁盤I/O操作;第二種就是在表中建立索引,然後在索引中找到符合查詢條件的索引值,最後通過保存在索引中的ROWID(相當於頁碼)快速找到表中對應的記錄。',0,0,0,0,0);
-- 時間: 0.012s
INSERT INTO `test`.`user`(`id`, `name`, `gender`, `age`, `email`, `message`, `a`, `b`, `c`, `d`,`state`) VALUES (2, '2', 'M', 24, '[email protected]', '在關係數據庫中,索引是一種單獨的、物理的對數據庫表中一列或多列的值進行排序的一種存儲結構,它是某個表中一列或若干列值的集合和相應的指向表中物理標識這些值的數據頁的邏輯指針清單。索引的作用相當於圖書的目錄,可以根據目錄中的頁碼快速找到所需的內容。\r\n索引提供指向存儲在表的指定列中的數據值的指針,然後根據您指定的排序順序對這些指針排序。數據庫使用索引以找到特定值,然後順指針找到包含該值的行。這樣可以使對應於表的SQL語句執行得更快,可快速訪問數據庫表中的特定信息。\r\n當表中有大量記錄時,若要對錶進行查詢,第一種搜索信息方式是全表搜索,是將所有記錄一一取出,和查詢條件進行一一對比,然後返回滿足條件的記錄,這樣做會消耗大量數據庫系統時間,並造成大量磁盤I/O操作;第二種就是在表中建立索引,然後在索引中找到符合查詢條件的索引值,最後通過保存在索引中的ROWID(相當於頁碼)快速找到表中對應的記錄。',0,0,0,0,0);
-- 時間: 0.022s
INSERT INTO `test`.`user`(`id`, `name`, `gender`, `age`, `email`, `message`, `a`, `b`, `c`, `d`,`state`) VALUES (3, '3', 'F', 5, '[email protected]', '在關係數據庫中,索引是一種單獨的、物理的對數據庫表中一列或多列的值進行排序的一種存儲結構,它是某個表中一列或若干列值的集合和相應的指向表中物理標識這些值的數據頁的邏輯指針清單。索引的作用相當於圖書的目錄,可以根據目錄中的頁碼快速找到所需的內容。\r\n索引提供指向存儲在表的指定列中的數據值的指針,然後根據您指定的排序順序對這些指針排序。數據庫使用索引以找到特定值,然後順指針找到包含該值的行。這樣可以使對應於表的SQL語句執行得更快,可快速訪問數據庫表中的特定信息。\r\n當表中有大量記錄時,若要對錶進行查詢,第一種搜索信息方式是全表搜索,是將所有記錄一一取出,和查詢條件進行一一對比,然後返回滿足條件的記錄,這樣做會消耗大量數據庫系統時間,並造成大量磁盤I/O操作;第二種就是在表中建立索引,然後在索引中找到符合查詢條件的索引值,最後通過保存在索引中的ROWID(相當於頁碼)快速找到表中對應的記錄。',0,0,0,0,0);
-- 時間: 0.016s
INSERT INTO `test`.`user`(`id`, `name`, `gender`, `age`, `email`, `message`, `a`, `b`, `c`, `d`,`state`) VALUES (4, '4', 'M', 67, '[email protected]', '在關係數據庫中,索引是一種單獨的、物理的對數據庫表中一列或多列的值進行排序的一種存儲結構,它是某個表中一列或若干列值的集合和相應的指向表中物理標識這些值的數據頁的邏輯指針清單。索引的作用相當於圖書的目錄,可以根據目錄中的頁碼快速找到所需的內容。\r\n索引提供指向存儲在表的指定列中的數據值的指針,然後根據您指定的排序順序對這些指針排序。數據庫使用索引以找到特定值,然後順指針找到包含該值的行。這樣可以使對應於表的SQL語句執行得更快,可快速訪問數據庫表中的特定信息。\r\n當表中有大量記錄時,若要對錶進行查詢,第一種搜索信息方式是全表搜索,是將所有記錄一一取出,和查詢條件進行一一對比,然後返回滿足條件的記錄,這樣做會消耗大量數據庫系統時間,並造成大量磁盤I/O操作;第二種就是在表中建立索引,然後在索引中找到符合查詢條件的索引值,最後通過保存在索引中的ROWID(相當於頁碼)快速找到表中對應的記錄。',0,0,0,0,0);
-- 時間: 0.016s
INSERT INTO `test`.`user`(`id`, `name`, `gender`, `age`, `email`, `message`, `a`, `b`, `c`, `d`,`state`) VALUES (5, '5', 'M', 37, '[email protected]', '在關係數據庫中,索引是一種單獨的、物理的對數據庫表中一列或多列的值進行排序的一種存儲結構,它是某個表中一列或若干列值的集合和相應的指向表中物理標識這些值的數據頁的邏輯指針清單。索引的作用相當於圖書的目錄,可以根據目錄中的頁碼快速找到所需的內容。\r\n索引提供指向存儲在表的指定列中的數據值的指針,然後根據您指定的排序順序對這些指針排序。數據庫使用索引以找到特定值,然後順指針找到包含該值的行。這樣可以使對應於表的SQL語句執行得更快,可快速訪問數據庫表中的特定信息。\r\n當表中有大量記錄時,若要對錶進行查詢,第一種搜索信息方式是全表搜索,是將所有記錄一一取出,和查詢條件進行一一對比,然後返回滿足條件的記錄,這樣做會消耗大量數據庫系統時間,並造成大量磁盤I/O操作;第二種就是在表中建立索引,然後在索引中找到符合查詢條件的索引值,最後通過保存在索引中的ROWID(相當於頁碼)快速找到表中對應的記錄。',0,0,0,0,1);
第二,插入10萬級別數據
-- Affected rows: 5 時間: 0.032s
-- Affected rows: 10 時間: 0.026s
-- Affected rows: 20 時間: 0.072s
-- Affected rows: 40 時間: 0.035s
-- Affected rows: 80 時間: 0.007s
-- Affected rows: 160 時間: 0.012s
-- Affected rows: 320 時間: 0.11s
-- Affected rows: 640 時間: 0.037s
-- Affected rows: 1280 時間: 0.044s
-- Affected rows: 2560 時間: 0.083s
-- Affected rows: 5120 時間: 0.223s
-- Affected rows: 10240 時間: 0.252s
-- Affected rows: 20480 時間: 0.603s
-- Affected rows: 40960 時間: 0.93s
-- Affected rows: 81920 時間: 2.728s
-- 第一步:執行15次,數據量大概爲163840 ,爲十萬級別
INSERT into user SELECT null,t.`name`,t.gender,t.age,t.email,t.message,t.a,t.b,t.c,t.d,t.state FROM `user` t;
-- 第二步:更新a、b、c和d
-- > Affected rows: 163840 時間: 11.979s
update user set `name` = id,`a` = id,`b` = id,`c`=id,`d`=id ;
(3)檢查
第一,表結構
desc user ;
第二,索引
show index from user;
第三,表信息
show table status from test where name='user';
第四,表數據
-- 查看前100條記錄 時間: 0.001s
SELECT * FROM user t limit 100;
-- 數量:163840 時間: 2.011s
SELECT count(*) FROM user t ;
2、user_detail
(1)表結構
-- 時間: 0s
SET NAMES utf8mb4;
-- 時間: 0s
SET FOREIGN_KEY_CHECKS = 0;
-- 時間: 0.001s
DROP TABLE IF EXISTS `user_detail`;
CREATE TABLE `user_detail` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`uid` int(11) NULL DEFAULT NULL COMMENT '關聯user表的id',
`name` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '姓名',
`gender` char(1) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '性別:F-女;M-男',
`age` int(3) NULL DEFAULT NULL COMMENT '年齡',
`email` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '郵箱',
`message` text CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL COMMENT '個人信息',
`a` int(11) NULL DEFAULT NULL,
`b` int(11) NULL DEFAULT NULL,
`c` int(11) NULL DEFAULT NULL,
`d` int(11) NULL DEFAULT NULL,
PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 1 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci ROW_FORMAT = Dynamic;
-- 時間: 0.014s
SET FOREIGN_KEY_CHECKS = 1;
(2)數據
-- 插入1000條數據
-- Affected rows: 1000 時間: 0.153s
INSERT into user_detail SELECT t.id,t.id,t.name,t.gender,t.age,t.email,t.message,t.a,t.b,t.c,t.d FROM `user` t limit 1000;
(3)檢查
第一,表結構
desc user_detail ;
第二,索引
show index from user_detail;
第三,表信息
show table status from test where name='user_detail';
第四,表數據
-- 查看前100條記錄 時間: 0.001s
SELECT * FROM user_detail t limit 100;
-- 數量:1000 時間: 0.079s
SELECT count(*) FROM user_detail t ;
3、user_account
(1)表結構
-- 時間: 0s
SET FOREIGN_KEY_CHECKS=0;
-- 時間: 0s
DROP TABLE IF EXISTS `user_account`;
-- 時間: 0.054s
CREATE TABLE `user_account` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`username` varchar(50) DEFAULT NULL COMMENT '賬號',
`password` varchar(50) DEFAULT NULL COMMENT '密碼',
`salt` int(11) DEFAULT 0 COMMENT '鹽值',
`sort` int(11) DEFAULT 0 COMMENT '排序',
`state` int(1) DEFAULT '1' COMMENT '狀態:0無效1有效',
`remark` VARCHAR(100) DEFAULT null COMMENT '備註',
PRIMARY KEY (`id`) USING BTREE
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4 ROW_FORMAT=COMPACT;
-- 時間: 0.007s
SET FOREIGN_KEY_CHECKS = 1;
(2)數據
第一,插入基礎數據
-- Affected rows: 1 時間: 0.521s
INSERT INTO `user_account` VALUES (null, '1', '1', 1, 1, 1, '備註');
-- Affected rows: 1 時間: 0.018s
INSERT INTO `user_account` VALUES (null, '2', '2', 2, 2, 1, '備註');
-- Affected rows: 1 時間: 0.016s
INSERT INTO `user_account` VALUES (null, '3', '3', 3, 3, 1, '備註');
-- Affected rows: 1 時間: 0.051s
INSERT INTO `user_account` VALUES (null, '4', '4', 4, 4, 1, '備註');
-- Affected rows: 1 時間: 0.017s
INSERT INTO `user_account` VALUES (null, '5', '5', 5, 5, 0, '備註');
第二,插入千萬級別數據
-- Affected rows: 5 時間: 0.066s
-- Affected rows: 10 時間: 0.04s
-- Affected rows: 20 時間: 0.056s
-- Affected rows: 40 時間: 0.025s
-- Affected rows: 80 時間: 0.018s
-- Affected rows: 160 時間: 0.014s
-- Affected rows: 320 時間: 0.095s
-- Affected rows: 640 時間: 0.077s
-- Affected rows: 1280 時間: 0.094s
-- Affected rows: 2560 時間: 0.304s
-- Affected rows: 5120 時間: 0.302s
-- Affected rows: 10240 時間: 0.959s
-- Affected rows: 20480 時間: 0.677s
-- Affected rows: 40960 時間: 1.481s
-- Affected rows: 81920 時間: 4.912s
-- Affected rows: 163840 時間: 6.598s
-- Affected rows: 327680 時間: 7.989s
-- Affected rows: 655360 時間: 11.656s
-- Affected rows: 1310720 時間: 16.586s
-- Affected rows: 2621440 時間: 34.713s
-- Affected rows: 5242880 時間: 86.015s
-- 第一步:執行21次,數據量大概爲10485760,爲千萬級別
INSERT into user_account SELECT null,t.username,t.`password`,t.salt,t.sort,t.state,t.remark FROM `user_account` t;
-- 第二步:更新username、password、salt和sort
-- Affected rows: 10485755 時間: 479.257s
update user_account set `username` = id,`password` = id,`salt`=id,`sort`=id ;
-- 第三步:更新remark
-- Affected rows: 943384 時間: 35.478s
update user_account set remark = null where id < 1139965;
-- Affected rows: 1393115 時間: 31.097s
update user_account set remark = null where id > 9485760;
(3)檢查
第一,表結構
desc user_account ;
說明:
第二,索引
show index from user_account;
第三,表信息
show table status from test where name='user_account';
第四,表數據
-- 查看前100條記錄
SELECT * FROM user_account t limit 100;
-- 數量:10485760 第一次查詢時間: 9.837s 第二次查詢時間: 5.44s 第三次查詢時間: 3.592s 時間: 2.626s 時間: 2.634s 時間: 2.656s
SELECT count(*) FROM user_account t ;
4、相關SQL
後面的實驗環節會經常用到
ALTER TABLE user_detail ADD INDEX index_user_detail_uid (uid);
ALTER TABLE user ADD INDEX index_user_a (a);
ALTER TABLE user ADD INDEX index_user_b (b);
ALTER TABLE user ADD UNIQUE INDEX index_user_name (name);
drop INDEX index_user_detail_uid on user_detail ;
drop INDEX index_user_a on user ;
drop INDEX index_user_b on user ;
drop INDEX index_user_name on user ;
SHOW INDEX FROM user_account;
(二)EXPLAIN結果列詳解
在MySQL中,我們可以通過EXPLAIN命令獲取MySQL如何執行SELECT語句的信息,包括在SELECT語句執行過程中表如何連接和連接的順序。
EXPLAIN SELECT * FROM user ;
EXPLAIN SELECT * FROM user_detail ;
EXPLAIN SELECT * FROM user_account ;
user:
user_detail:
user_account:
下面分別對EXPLAIN命令結果的每一列進行說明:
1、select_type
表示SELECT的類型,常見的取值有:
類型 | 說明 |
---|---|
SIMPLE | 簡單表,不使用表連接或子查詢 |
PRIMARY | 主查詢,即外層的查詢 |
UNION | UNION中的第二個或者後面的查詢語句 |
SUBQUERY | 子查詢中的第一個 |
(1)SIMPLE
EXPLAIN
select * from user v1 where v1.id < 1000;
(2)PRIMARY
第一,先給user_detail表的uid字段建立索引
-- 時間: 0.256s
ALTER TABLE user_detail ADD INDEX index_user_detail_uid (uid);
第二,測試SQL
EXPLAIN
select * from user v1 where v1.id < 1000
union all
select * from user v2 where v2.id > 100000
union all
select * from user v3 where v3.id = 163840 ;
(3)UNION
EXPLAIN
select * from user v1 where v1.id < 1000
union
select * from user v2 where v2.id > 100000
union
select * from user v3 where v3.id = 163840 ;
(4)SUBQUERY
EXPLAIN
select
v1.id,
(select v2.uid from user_detail v2 where v2.id = v1.id limit 1) ,
(select v2.gender from user_detail v2 where v2.id = v1.id limit 1) ,
v1.name,
(select v2.age from user_detail v2 where v2.id = v1.id limit 1)
from user v1 ;
2、table:
輸出結果集的表(表別名)
EXPLAIN
select
v1.id,
(select v2.uid from user_detail v2 where v2.id = v1.id limit 1) ,
(select v2.gender from user_detail v2 where v2.id = v1.id limit 1) ,
v1.name,
(select v2.age from user_detail v2 where v2.id = v1.id limit 1)
from user v1 ;
3、type:
表示MySQL在表中找到所需行的方式,或者叫訪問類型。常見訪問類型如下,從上到下,性能由差到最好:
ALL | 全表掃描 |
---|---|
index | 索引全掃描 |
range | 索引範圍掃描 |
ref | 非唯一索引掃描 |
eq_ref | 唯一索引掃描 |
const,system | 單表最多有一個匹配行 |
NULL | 不用掃描表或索引 |
(1)type=ALL
全表掃描,MySQL遍歷全表來找到匹配行
一般是沒有where條件或者where條件沒有使用索引的查詢語句
EXPLAIN SELECT * FROM user ;
-- gender無索引
EXPLAIN SELECT * FROM user WHERE gender = 'F';
(2)type=index,
索引全掃描,MySQL遍歷整個索引來查詢匹配行,並不會掃描表
一般是查詢的字段(列)都有索引的查詢語句,如SELECT id
EXPLAIN SELECT id FROM user;
(3)type=range
索引範圍掃描,常用於<、<=、>、>=、between等操作
第一,查看索引
show index from user_detail;
第二,測試點1:沒有加索引
注意這種情況下比較的字段是需要加索引的,如果沒有索引,則MySQL會進行全表掃描,如下面這種情況,gender字段沒有加索引:
EXPLAIN SELECT * FROM user WHERE a>10 AND b<20;
第三,索引準備
-- 時間: 0.969s
ALTER TABLE user ADD INDEX index_user_a (a);
-- 時間: 0.921s
ALTER TABLE user ADD INDEX index_user_b (b);
第四,測試點2:加上索引後
EXPLAIN SELECT * FROM user WHERE a>10 AND b<20;
(4)type=ref
使用非唯一索引或唯一索引的前綴掃描,返回匹配某個單獨值的記錄行
第一,測試點1:字段a
存在普通索引(非唯一索引)
EXPLAIN SELECT * FROM user WHERE a = 13;
第二,測試點2:ref類型還經常會出現在join操作中:
先看一下需要測試的表的數量
-- 數據量:163840 時間: 0.021s
select count(*) from user ;
-- 數據量:1000 時間: 0s
select count(*) from user_detail ;
-- 10485760 時間: 40.265s 時間: 5.084s 時間: 4.986s 時間: 5.123s
select count(*) from user_account ;
測試SQL
EXPLAIN
SELECT *
FROM user v1
INNER JOIN user_detail v2
ON v1.id = v2.uid ;
user、user_detail表關聯查詢,關聯字段v1.id
(主鍵),v2.uid
(非唯一索引)。表關聯查詢時必定會有一張表進行全表掃描,此表一定是幾張表中記錄行數最少的表,然後再通過非唯一索引尋找其他關聯表中的匹配行,以此達到表關聯時掃描行數最少。
因爲user、user_detail兩表中user_detail表的記錄行數最少,所以user_detail表進行全表掃描,user表通過非唯一索引尋找匹配行。
(5)type=eq_ref
類似ref,區別在於使用的索引是唯一索引,對於每個索引鍵值,表中只有一條記錄匹配
eq_ref一般出現在多表連接時使用primary key或者unique index作爲關聯條件。
user、user_detail表關聯查詢和上一條所說的基本一致,只不過關聯條件由非唯一索引變成了主鍵。
EXPLAIN
SELECT *
FROM user v1
INNER JOIN user_detail v2
ON user.id = v2.id;
(6)type=const/system
單表中最多有一條匹配行,查詢起來非常迅速,所以這個匹配行的其他列的值可以被優化器在當前查詢中當作常量來處理
const/system出現在根據主鍵primary key或者唯一索引unique index 進行的查詢
第一,根據主鍵primary key進行的查詢:
EXPLAIN SELECT * FROM user WHERE id = 8;
第二,根據唯一索引unique index進行的查詢:
索引準備
-- 時間: 3.474s
ALTER TABLE user ADD UNIQUE INDEX index_user_name (name);
測試SQL
EXPLAIN SELECT * FROM user WHERE name ='8';
(7)type=NULL
MySQL不用訪問表或者索引,直接就能夠得到結果
EXPLAIN select 1 from DUAL where 1 ;
4、possible_keys:
表示查詢可能使用的索引。
第一,索引準備
-- 時間: 0.969s
ALTER TABLE user ADD INDEX index_user_a (a);
-- 時間: 0.921s
ALTER TABLE user ADD INDEX index_user_b (b);
第二,測試點
EXPLAIN SELECT * FROM user WHERE a>10 AND b<20;
如圖,因爲where條件中的兩個都是索引,故可能用到兩個索引:index_user_a、index_user_b
5、key:
實際使用的索引。
如上圖,因爲使用index_user_b消耗比index_user_a小,所以實際使用的索引爲index_user_b。
6、key_len:
使用索引字段的長度
如上圖,所以的長度爲5。
7、ref:
使用哪個列或常數與key一起從表中選擇行。
顯示索引的哪一列被使用了,有時候會是一個常量:表示哪些列或常量被用於用於查找索引列上的值。
形式可以爲以下兩種:
- 庫.表.字段
EXPLAIN
SELECT *
FROM user v1
INNER JOIN user_detail v2
ON user.id = v2.id;
- 常量
EXPLAIN SELECT * FROM user WHERE name ='8';
8、rows:
掃描行的數量
9、filtered:
存儲引擎返回的數據在server層過濾後,剩下多少滿足查詢的記錄數量的比例(百分比)
10、Extra:
執行情況的說明和描述,包含不適合在其他列中顯示但是對執行計劃非常重要的額外信息
最主要的有一下三種:
Using Index | 表示索引覆蓋,不會回表查詢 |
---|---|
Using Where | 表示進行了回表查詢 |
Using Index Condition | 表示進行了ICP優化 |
Using Flesort | 表示MySQL需額外排序操作, 不能通過索引順序達到排序效果 |
什麼是ICP?
MySQL5.6引入了**Index Condition Pushdown(ICP)**的特性,進一步優化了查詢。Pushdown表示操作下放,某些情況下的條件過濾操作下放到存儲引擎。
測試SQL
EXPLAIN SELECT * FROM user
WHERE a = 13
AND id>=50
AND id<=400;
在5.6版本之前:
優化器首先使用複合索引index_user_a_b_b_d過濾出符合條件a = 13
的記錄,然後根據複合索引index_user_a_b_b_d回表獲取記錄,最終根據條件id>=50 AND id<=400
過濾出最後的查詢結果(在服務層完成)。
在5.6版本之後:
MySQL使用了ICP來進一步優化查詢,在檢索的時候,把條件id>=50 AND id<=400
也推到存儲引擎層完成過濾,這樣能夠降低不必要的IO訪問。Extra爲Using index condition
就表示使用了ICP優化。
五、實驗總結(包括心得體會、問題回答及實驗改進意見)
1、通過本次實驗,理解了EXPLAIN的相關概念
2、熟悉了EXPLAIN結果列
3、掌握了EXPLAIN的使用。
六、參考
《深入淺出MySQL》