數據結構-索引-實驗1:EXPLAIN分析SQL的執行計劃

數據結構-索引-實驗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(非唯一索引)。表關聯查詢時必定會有一張表進行全表掃描,此表一定是幾張表中記錄行數最少的表,然後再通過非唯一索引尋找其他關聯表中的匹配行,以此達到表關聯時掃描行數最少。

因爲useruser_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》

MySQL——通過EXPLAIN分析SQL的執行計劃

發佈了33 篇原創文章 · 獲贊 15 · 訪問量 3萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章