最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

MySQL EXPLAIN 從入門到實(shí)戰(zhàn)完全指南

 更新時間:2025年12月17日 09:34:37   作者:·云揚(yáng)·  
本文詳細(xì)介紹了MySQL的EXPLAIN工具,該工具可以幫助開發(fā)者理解SQL查詢的執(zhí)行計(jì)劃,從而優(yōu)化查詢性能,本文結(jié)合實(shí)例代碼給大家介紹的非常詳細(xì),感興趣的朋友跟隨小編一起看看吧

在日常開發(fā)中,我們經(jīng)常會遇到 SQL 執(zhí)行緩慢的問題。此時,MySQL EXPLAIN 便是排查性能瓶頸的“利器”——它能清晰展示 SQL 的執(zhí)行計(jì)劃,幫助我們判斷索引是否生效、是否存在全表掃描、是否需要優(yōu)化排序等。本文將從測試環(huán)境搭建開始,逐步拆解 EXPLAIN 的核心字段含義,并通過實(shí)戰(zhàn)案例講解如何利用它優(yōu)化 SQL 性能,最后介紹 MySQL 8.0 帶來的執(zhí)行計(jì)劃新特性。

一、準(zhǔn)備:搭建測試環(huán)境

為了讓大家更直觀地理解 EXPLAIN 的用法,我們先創(chuàng)建一套測試數(shù)據(jù)。以下 SQL 可直接在 MySQL 中執(zhí)行,用于生成數(shù)據(jù)庫、表結(jié)構(gòu)及模擬數(shù)據(jù)。

1.1 創(chuàng)建數(shù)據(jù)庫與表

-- 1. 創(chuàng)建測試數(shù)據(jù)庫 martin
CREATE DATABASE martin;
USE martin;
-- 2. 創(chuàng)建表 t1(含主鍵與普通索引)
DROP TABLE IF EXISTS t1;
CREATE TABLE `t1` (
  `id` int NOT NULL AUTO_INCREMENT,
  `a` int DEFAULT NULL,
  `b` int DEFAULT NULL,
  `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '記錄創(chuàng)建時間',
  `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '記錄更新時間',
  PRIMARY KEY (`id`),  -- 主鍵索引
  KEY `idx_a` (`a`),   -- 普通索引 a
  KEY `idx_b` (`b`)    -- 普通索引 b
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
-- 3. 創(chuàng)建存儲過程,批量插入 1000 條數(shù)據(jù)
DROP PROCEDURE IF EXISTS insert_t1;
DELIMITER ;;
CREATE PROCEDURE insert_t1()
BEGIN
  DECLARE i int;
  SET i = 1;
  WHILE (i <= 1000) DO
    INSERT INTO t1(a, b) VALUES(i, i);
    SET i = i + 1;
  END WHILE;
END;;
DELIMITER ;
CALL insert_t1();  -- 調(diào)用存儲過程插入數(shù)據(jù)
-- 4. 復(fù)制 t1 表結(jié)構(gòu)與數(shù)據(jù)到 t2
DROP TABLE IF EXISTS t2;
CREATE TABLE t2 LIKE t1;
INSERT INTO t2 SELECT * FROM t1;

1.2 初識 EXPLAIN

執(zhí)行以下語句,即可查看 SQL 的執(zhí)行計(jì)劃:

EXPLAIN SELECT * FROM t1 WHERE b = 100;

執(zhí)行后會返回一張包含 12 個字段的表格,這些字段便是我們分析 SQL 性能的核心依據(jù)。接下來,我們逐一拆解這些字段的含義。

二、EXPLAIN 核心字段詳解

EXPLAIN 結(jié)果包含 id、select_type、table、type 等 12 個字段,其中 select_type、type、key、key_len、Extra 是需要重點(diǎn)關(guān)注的核心字段(下文已標(biāo)粗)。

列名解釋
id查詢編號,用于標(biāo)識多表關(guān)聯(lián)或子查詢中的執(zhí)行順序
select_type查詢類型,區(qū)分簡單查詢、子查詢、聯(lián)合查詢等
table執(zhí)行查詢涉及的表
partitions匹配的分區(qū)(僅分區(qū)表有效,非分區(qū)表為 NULL)
type表連接/查詢類型,直接反映查詢性能(從優(yōu)到差排序)
possible_keysMySQL 認(rèn)為可能用到的索引(僅供參考,不一定實(shí)際使用)
key實(shí)際使用的索引(若為 NULL,說明未使用索引)
key_len實(shí)際使用的索引長度(可用于判斷聯(lián)合索引的生效列數(shù))
ref與索引比較的列或常量(如 const 表示與常量比較)
rows預(yù)估需要掃描的行數(shù)(InnoDB 為估值,非精確值)
filtered按條件篩選后的行百分比(值越高,篩選效果越好)
Extra附加信息,包含性能優(yōu)化的關(guān)鍵提示(如是否全表掃描、是否使用臨時表等)

2.1 select_type:區(qū)分查詢類型

select_type 用于標(biāo)識查詢的復(fù)雜程度,常見值如下:

select_type 值解釋
SIMPLE簡單查詢(無關(guān)聯(lián)、無子查詢),最常見的類型
PRIMARY復(fù)雜查詢中的最外層查詢(如子查詢的外層、聯(lián)合查詢的第一個查詢)
UNION聯(lián)合查詢中第二個及以后的查詢(如 A UNION B 中的 B)
DEPENDENT UNION依賴外部查詢結(jié)果的聯(lián)合查詢(外層查詢的結(jié)果影響內(nèi)層聯(lián)合查詢)
SUBQUERY子查詢中的第一個查詢(不依賴外層結(jié)果)
DEPENDENT SUBQUERY依賴外層查詢結(jié)果的子查詢(外層每行都需觸發(fā)子查詢執(zhí)行)
DERIVED派生表查詢(如 FROM 子句中的子查詢,MySQL 會先將結(jié)果存入臨時表)
MATERIALIZED物化子查詢(MySQL 將子查詢結(jié)果緩存為臨時表,避免重復(fù)執(zhí)行)

示例:子查詢的 select_type

EXPLAIN SELECT * FROM t1 WHERE a = (SELECT a FROM t2 WHERE id = 10);

此時,子查詢 (SELECT a FROM t2 WHERE id = 10)select_typeSUBQUERY,外層查詢的 select_typePRIMARY。

2.2 type:判斷查詢性能等級

type 是 EXPLAIN 中最核心的字段之一,它表示表的查詢/連接方式,性能從優(yōu)到差依次為:
system > const > eq_ref > ref > fulltext > ref_or_null > index_merge > unique_subquery > index_subquery > range > index > ALL

type 值解釋適用場景示例
system表僅有 1 行數(shù)據(jù)(僅 MyISAM/Memory 引擎支持),性能最優(yōu)查詢 MyISAM 引擎的單行情報表
const基于主鍵/唯一索引的等值查詢,僅返回 1 行結(jié)果SELECT * FROM t1 WHERE id = 100
eq_ref多表關(guān)聯(lián)時,基于主鍵/唯一索引的等值匹配(每行僅匹配 1 行)SELECT * FROM t1 JOIN t2 ON t1.id = t2.id
ref基于普通索引的等值查詢,可能返回多行SELECT * FROM t1 WHERE b = 100(b 有普通索引)
range基于索引的范圍查詢(如 >、<、BETWEENINSELECT * FROM t1 WHERE a BETWEEN 100 AND 200
index全索引掃描(比全表掃描快,因索引文件更小)SELECT a FROM t1(a 有索引,僅掃描索引樹)
ALL全表掃描(性能最差,需避免)SELECT * FROM t1 WHERE create_time = '2024-01-01'(create_time 無索引)

優(yōu)化建議:實(shí)際開發(fā)中,應(yīng)盡量保證 type 至少達(dá)到 range 級別,避免 indexALL(全表/全索引掃描)。

2.3 key_len:判斷索引生效長度

key_len 表示實(shí)際使用的索引字節(jié)數(shù),可用于判斷 聯(lián)合索引的生效列數(shù)(需結(jié)合字段類型計(jì)算)。常見字段類型的 key_len 計(jì)算規(guī)則如下:

列類型key_len 計(jì)算方式備注
int(允許 NULL)4 + 1 = 5 字節(jié)int 占 4 字節(jié),NULL 需 1 字節(jié)標(biāo)記
int(NOT NULL)4 字節(jié)無 NULL 標(biāo)記,僅字段本身長度
bigint(允許 NULL)8 + 1 = 9 字節(jié)bigint 占 8 字節(jié)
char(30) utf8(NULL)30 * 3 + 1 = 91 字節(jié)utf8 中 1 字符占 3 字節(jié),char 是定長類型
varchar(30) utf8(NULL)30 * 3 + 2 + 1 = 93 字節(jié)varchar 是變長類型,需 2 字節(jié)存儲長度,NULL 需 1 字節(jié)標(biāo)記
datetime(MySQL 8.0)5 + 1 = 6 字節(jié)5.6.4 后 datetime 優(yōu)化為 5 字節(jié)存儲,NULL 需 1 字節(jié)

示例:聯(lián)合索引 idx_a_b(a, b),若查詢 WHERE a = 100key_len 為 5(int 允許 NULL);若查詢 WHERE a = 100 AND b = 200,key_len 為 5 + 5 = 10 字節(jié),說明聯(lián)合索引的兩列均生效。

2.4 Extra:性能優(yōu)化的關(guān)鍵提示

Extra 字段包含大量優(yōu)化相關(guān)的細(xì)節(jié),常見值及優(yōu)化建議如下:

Extra 值解釋優(yōu)化建議
Using filesort非索引排序(需在內(nèi)存/磁盤排序,性能差)給排序字段添加索引(如 ORDER BY create_timeidx_create_time
Using temporary創(chuàng)建臨時表存儲中間結(jié)果(常見于無索引的 GROUP BY)給 GROUP BY 字段添加索引
Using index覆蓋索引(僅掃描索引即可獲取結(jié)果,無需回表,性能優(yōu))保持查詢字段在索引中(如 SELECT a FROM t1idx_a
Using where需通過 WHERE 篩選結(jié)果(若結(jié)合全表掃描,需優(yōu)化)給 WHERE 條件字段添加索引
Impossible WHEREWHERE 條件恒為 false(如 1 < 0),無數(shù)據(jù)返回檢查條件邏輯,避免無效查詢
Using join buffer關(guān)聯(lián)查詢中,被驅(qū)動表無索引,需用連接緩沖區(qū)(性能差)給被驅(qū)動表的關(guān)聯(lián)字段添加索引
Select tables optimized away用聚合函數(shù)(max/min)訪問索引字段,MySQL 直接優(yōu)化為索引查找無需優(yōu)化,已是最優(yōu)狀態(tài)

示例Using filesort 優(yōu)化前:

-- 無索引的 ORDER BY,出現(xiàn) Using filesort
EXPLAIN SELECT * FROM t1 ORDER BY create_time;

優(yōu)化后(添加索引):

ALTER TABLE t1 ADD INDEX idx_create_time(create_time);
EXPLAIN SELECT * FROM t1 ORDER BY create_time;  -- 無 Using filesort

三、實(shí)戰(zhàn):EXPLAIN 優(yōu)化案例

理論結(jié)合實(shí)踐才能更好地掌握 EXPLAIN,以下通過 3 個實(shí)戰(zhàn)案例,展示如何用 EXPLAIN 定位并解決性能問題。

3.1 案例 1:對比有無索引的執(zhí)行計(jì)劃

索引是優(yōu)化 SQL 的核心手段,我們通過 EXPLAIN 對比“主鍵查詢”“有索引查詢”“無索引查詢”的差異:

查詢場景SQL 語句type 類型key 索引性能結(jié)論
主鍵查詢(有唯一索引)EXPLAIN SELECT * FROM t1 WHERE id = 100constPRIMARY最優(yōu),僅掃描 1 行
普通索引查詢EXPLAIN SELECT * FROM t1 WHERE b = 100refidx_b優(yōu)秀,掃描少量行
無索引查詢(刪除 idx_b)ALTER TABLE t1 DROP INDEX idx_b;
EXPLAIN SELECT * FROM t1 WHERE b = 100
ALLNULL最差,全表掃描 1000 行

結(jié)論:索引能顯著降低掃描行數(shù),將 typeALL(全表)提升至 refconst

3.2 案例 2:分析分區(qū)表的執(zhí)行計(jì)劃

對于海量數(shù)據(jù),分區(qū)表是常用方案。EXPLAIN 的 partitions 字段可展示查詢命中的分區(qū),幫助驗(yàn)證分區(qū)有效性。

步驟 1:創(chuàng)建分區(qū)表

CREATE TABLE sales (
  sale_id INT,
  sale_date DATE,
  amount DECIMAL(10, 2)
) PARTITION BY RANGE (YEAR(sale_date)) (  -- 按年份分區(qū)
  PARTITION p2022 VALUES LESS THAN (2023),
  PARTITION p2023 VALUES LESS THAN (2024),
  PARTITION p2024 VALUES LESS THAN MAXVALUE
);
-- 插入 2022-2024 年數(shù)據(jù)
INSERT INTO sales (sale_id, sale_date, amount)
VALUES
(1, '2022-01-01', 100.50),
(8, '2024-08-23', 270.60),
(10, '2024-10-05', 280.75);

步驟 2:查看分區(qū)執(zhí)行計(jì)劃

-- 查詢 2024 年數(shù)據(jù),僅命中 p2024 分區(qū)
EXPLAIN SELECT * FROM sales WHERE sale_date = '2024-08-23';
-- 查詢 2023 年后數(shù)據(jù),命中 p2023、p2024 分區(qū)
EXPLAIN SELECT * FROM sales WHERE sale_date > '2023-01-01';

此時 partitions 字段會顯示 p2024p2023,p2024,說明分區(qū)生效,避免了全分區(qū)掃描。

3.3 案例 3:排查正在執(zhí)行的慢查詢

當(dāng)生產(chǎn)環(huán)境出現(xiàn)慢查詢時,可通過 EXPLAIN FOR CONNECTION 查看其執(zhí)行計(jì)劃,無需等待查詢結(jié)束。

步驟 1:構(gòu)造慢查詢

在窗口 1 執(zhí)行一條含 sleep(100) 的慢查詢:

SELECT *, SLEEP(100) FROM t1 LIMIT 1;  -- 執(zhí)行時間約 100 秒

步驟 2:獲取連接 ID

在窗口 2 執(zhí)行 show processlist,找到慢查詢的 Id(如 12):

show processlist;

步驟 3:查看慢查詢執(zhí)行計(jì)劃

EXPLAIN FOR CONNECTION 12;  -- 12 為慢查詢的 Id

通過此方式,可快速定位慢查詢是否存在全表掃描、未使用索引等問題,及時優(yōu)化。

四、MySQL 8.0 執(zhí)行計(jì)劃新特性

MySQL 8.0 對 EXPLAIN 進(jìn)行了增強(qiáng),新增了 樹狀執(zhí)行計(jì)劃EXPLAIN ANALYZE,進(jìn)一步提升了優(yōu)化效率。

4.1 樹狀執(zhí)行計(jì)劃(format=tree)

從 MySQL 8.0.16 開始,支持輸出樹狀結(jié)構(gòu)的執(zhí)行計(jì)劃,更直觀地展示查詢邏輯(如關(guān)聯(lián)順序、過濾條件)。

EXPLAIN FORMAT=TREE SELECT * FROM t1 WHERE a = 100;

執(zhí)行結(jié)果如下(結(jié)構(gòu)清晰,包含預(yù)估成本和行數(shù)):

-> Rows fetched before execution (cost=0.25 rows=1)
    -> Index lookup on t1 using idx_a (a=100) (cost=0.25 rows=1)

4.2 EXPLAIN ANALYZE(實(shí)際執(zhí)行分析)

從 MySQL 8.0.18 開始,EXPLAIN ANALYZE實(shí)際執(zhí)行 SQL,并返回更精確的執(zhí)行信息(如實(shí)際掃描行數(shù)、執(zhí)行時間、循環(huán)次數(shù)),解決了傳統(tǒng) EXPLAIN 估值不準(zhǔn)的問題。

EXPLAIN ANALYZE SELECT * FROM t1 WHERE a BETWEEN 100 AND 200;

執(zhí)行結(jié)果包含以下關(guān)鍵信息:

  • actual time: 實(shí)際執(zhí)行時間(如 0.02 秒)
  • actual rows: 實(shí)際掃描行數(shù)(如 101 行)
  • loops: 循環(huán)次數(shù)(如 1 次)

注意EXPLAIN ANALYZE 會執(zhí)行 SQL,若為寫操作(如 INSERT/UPDATE),需先備份數(shù)據(jù)或在測試環(huán)境使用。

五、總結(jié)

EXPLAIN 是 MySQL 性能優(yōu)化的“基石”,掌握它的核心要點(diǎn)可幫助我們快速定位問題:

  1. 重點(diǎn)關(guān)注字段type(性能等級)、key(實(shí)際索引)、Extra(優(yōu)化提示);
  2. 索引優(yōu)化原則:避免 type=ALL(全表掃描),消除 Using filesortUsing temporary
  3. 實(shí)戰(zhàn)技巧:用 EXPLAIN FOR CONNECTION 排查慢查詢,用 MySQL 8.0 的 EXPLAIN ANALYZE 獲取精確執(zhí)行信息。

希望本文能幫助你更好地利用 EXPLAIN 優(yōu)化 SQL 性能,讓數(shù)據(jù)庫查詢更高效!

到此這篇關(guān)于MySQL EXPLAIN 從入門到實(shí)戰(zhàn)完全指南的文章就介紹到這了,更多相關(guān)mysql explain實(shí)戰(zhàn)內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

最新評論

甘谷县| 九龙坡区| 齐河县| 伊宁县| 四川省| 祁门县| 张家口市| 古蔺县| 临邑县| 砚山县| 青冈县| 阿拉尔市| 安国市| 漳浦县| 淄博市| 新昌县| 五华县| 泰兴市| 利津县| 丰台区| 北流市| 云林县| 朔州市| 辽阳市| 都江堰市| 嘉善县| 肃南| 大田县| 罗定市| 莒南县| 阜康市| 丹凤县| 霞浦县| 南靖县| 获嘉县| 沙雅县| 定南县| 秦皇岛市| 衡南县| 宿州市| 寿宁县|