一、什么是 EXPLAIN 命令?
EXPLAIN
命令用于顯示 MySQL 如何執行某個 SQL 語句,尤其是 SELECT 語句。通過 EXPLAIN
命令,可以看到查詢在實際執行前的執行計劃,這對于優化查詢性能至關重要。
二、EXPLAIN 的基本用法
要使用 EXPLAIN
命令,只需在你的 SELECT 語句前加上 EXPLAIN
關鍵字即可。例如:
EXPLAIN SELECT * FROM employees WHERE department = 'Sales';
執行上述命令后,MySQL 會返回一個結果集,包含關于查詢執行計劃的詳細信息。下面我們逐一解釋這些信息。
三、EXPLAIN 結果各列的含義
EXPLAIN
命令的結果集通常包含以下幾列:
id
select_type
table
partitions
type
possible_keys
key
key_len
ref
rows
filtered
Extra
id
id
列表示查詢中每個 SELECT 子句的標識符。單個查詢的 id 值通常是 1,子查詢和聯合查詢的 id 值可能不同。
select_type
select_type
列表示 SELECT 的類型,常見的值有:
SIMPLE
:簡單的 SELECT 查詢,不包含子查詢或聯合查詢。PRIMARY
:最外層的 SELECT 查詢。UNION
:UNION 中的第二個或后續的 SELECT 查詢。DEPENDENT UNION
:UNION 中的第二個或后續的 SELECT 查詢,依賴于外部查詢。UNION RESULT
:UNION 的結果。SUBQUERY
:子查詢中的第一個 SELECT。DEPENDENT SUBQUERY
:子查詢中的第一個 SELECT,依賴于外部查詢。DERIVED
:派生表(子查詢的 FROM 子句)。
table
table
列表示正在訪問的表的名稱。
partitions
partitions
列表示查詢涉及到的分區。如果表是分區表,此列將顯示實際訪問的分區。如果沒有使用分區,該列顯示 NULL
。
type(重點)
type
列表示連接類型(join type),反映了 MySQL 在執行查詢時使用的訪問方法。連接類型從最優到最差依次如下:
system
:表僅有一行(等于系統表),這是 const 類型的特例。const
:表最多有一個匹配行,這是非常快速的,因為匹配行在優化階段就讀取出來了。使用索引一般是一般是 唯一索引 或 主鍵索引。eq_ref
:對于每個來自前一張表的行組合,讀一行,這是最理想的連接類型。連接字段,使用索引一般是 唯一索引 或 主鍵索引。ref
:對于每個來自前一張表的行組合,讀出所有匹配某個單獨值的行。使用索引一般是普通索引。range
:檢索給定范圍內的行,使用一個索引來選擇行。index
:全索引掃描(與全表掃描類似,但遍歷索引樹)。ALL
:全表掃描。
possible_keys
possible_keys
列表示查詢可能使用的索引。
key(重點)
key
列表示實際使用的索引。如果沒有選擇索引,顯示 NULL
。
key_len
key_len
列表示使用的索引鍵的長度。這個值是 MySQL 決定使用哪個索引時考慮的。
ref
ref
列表示使用哪個列或常量與 key 一起從表中選擇行。
rows
rows
列表示 MySQL 估計為了找到所需的行,需要讀取的行數。
filtered
filtered
列表示經過表條件過濾后返回的行數百分比。這個值表示剩余行數相對于讀取的行數的百分比。計算公式為:filtered = (滿足表條件的記錄數 / 該表的總記錄數) * 100%。
注意如果使用索引查詢,那么 MySQL 可能不會掃全表,直接查出索引中返回的數據,filtered 會是 100。
Extra
Extra
列包含關于查詢的詳細信息,可能的值有:
Using index
:只使用索引信息而不讀取實際的行(覆蓋索引)。Using where
:使用 WHERE 子句來限制哪些行將與下一張表匹配或返回給用戶。Using temporary
:需要使用臨時表來存儲結果。Using filesort
:需要額外的傳遞來排序結果。
四、EXPLAIN 命令 type 字段 SQL 測試
4.1、const 類型測試
-- const 類型測試
drop table if exists user;
create table user (id int primary key,name varchar(20)
)engine=innodb;insert into user values(1,'ar414');
insert into user values(2,'zhangsan');
insert into user values(3,'lisi');
insert into user values(4,'wangwu');explain
select *
from user
where id = 1;
4.2、eq_ref 類型測試
-- eq_ref 類型測試
drop table if exists user_balance;
drop table if exists user;create table user (id int primary key,name varchar(20)
)engine=innodb;insert into user values(1,'ar414');
insert into user values(2,'zhangsan');
insert into user values(3,'lisi');
insert into user values(4,'wangwu');create table user_balance (uid int primary key,balance int
)engine=innodb;insert into user_balance values(1,100);
insert into user_balance values(2,200);
insert into user_balance values(3,300);
insert into user_balance values(4,400);explain
select *
from userleft join user_balance on user.id = user_balance.uid
where user.id = user_balance.uid;
4.3、ref 類型測試
-- ref 類型測試
drop table if exists user_balance;
drop table if exists user;create table user (id int primary key,name varchar(20)
)engine=innodb;insert into user values(1,'ar414');
insert into user values(2,'zhangsan');
insert into user values(3,'lisi');
insert into user values(4,'wangwu');create table user_balance (uid int,balance int,index(uid)
)engine=innodb;insert into user_balance values(1,100);
insert into user_balance values(2,200);
insert into user_balance values(3,300);
insert into user_balance values(4,400);
insert into user_balance values(5,500);explain
select *
from userleft join user_balance on user.id = user_balance.uid
where user.id = 1;explain select * from user_balance where uid = 1;
4.4、range 類型測試
-- range 類型測試
drop table if exists user;create table user (id int primary key,name varchar(20)
)engine=innodb;insert into user values(1,'ar414');
insert into user values(2,'zhangsan');
insert into user values(3,'lisi');
insert into user values(4,'wangwu');explain
select *
from user
where id between 1 and 2;explain
select *
from user
where id in (1, 2, 3);explain
select *
from user
where id > 1;
4.5、index 類型測試
-- index 類型測試
drop table if exists user;create table user (id int primary key,name varchar(20)
)engine=innodb;insert into user values(1,'ar414');
insert into user values(2,'zhangsan');
insert into user values(3,'lisi');
insert into user values(4,'wangwu');explain
select count(1)
from user;
4.6、ALL 類型測試
-- ALL 類型測試
drop table if exists user;create table user (id int,name varchar(20)
)engine=innodb;insert into user values(1,'ar414');
insert into user values(2,'zhangsan');
insert into user values(3,'lisi');
insert into user values(4,'wangwu');
insert into user values(5,'zhaoliu');explain
select *
from user
where id = 1;