MySQL EXPLAIN執(zhí)行計劃,如何分析?
在實際開發(fā)中,如果選擇的是 MySQL 數(shù)據(jù)庫,通常會使用EXPLAIN關(guān)鍵字來顯示查詢 SQL 的執(zhí)行計劃,從而幫助我們優(yōu)化查詢性能。那么,EXPLAIN是如何工作的?EXPLAIN結(jié)果里面的字段該如何理解,這篇文章,我們將詳細分析。
字段解析
當(dāng)我們對一個查詢語句執(zhí)行EXPLAIN時,EXPLAIN通常會返回以下字段,下面我們將對各個列的含義及其示例進行說明。
id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
1 | SIMPLE | users | NULL | ALL | NULL | NULL | NULL | NULL | 1000 | 10.00 | Using where |
(1) id
id表示查詢的標識符。如果一個查詢包含子查詢或聯(lián)合查詢,每個子查詢或聯(lián)合查詢都會有一個唯一的 id。比如:1
(2) select_type
select_type表示查詢的類型,表示查詢是簡單查詢、聯(lián)合查詢、子查詢等。
常見值:
- SIMPLE: 簡單查詢,不包含子查詢或聯(lián)合查詢。
- PRIMARY: 最外層查詢。
- SUBQUERY: 子查詢中的第一個 SELECT。
- DERIVED: 派生表(子查詢中的 FROM 子句)。
比如:SIMPLE
(3) table
table代表了查詢涉及的表名或別名。
比如:users
(4) partitions
partitions代表查詢涉及的分區(qū)(如果有)。比如:NULL
(5) type
type表示連接類型,反映了 MySQL 如何查找表中的行。
常見值(按效率從高到低排序):
- system: 表只有一行(等同于系統(tǒng)表)。
- const: 表最多有一個匹配行(主鍵或唯一索引)。
- eq_ref: 對于每個來自前表的行組合,從該表讀取一行。
- ref: 對于每個來自前表的行組合,從該表讀取所有匹配行。
- range: 只檢索給定范圍的行,使用索引來選擇行。
- index: 全索引掃描。
- ALL: 全表掃描。
比如:ref
(6) possible_keyspossible_keys表示 MySQL 認為可以使用的索引。比如:PRIMARY
(7) keykey表示實際使用的索引。比如:PRIMARY
(8) key_lenkey_len表示使用的索引的長度。比如:4
(9) refref顯示使用哪個列或常數(shù)與 key 一起從表中選擇行。比如:const
(10) rowsrows表示 MySQL 估計要掃描的行數(shù)。比如:1
(11) filtered
filtered表示返回結(jié)果的行占總行數(shù)的百分比。比如:100.00
(12) ExtraExtra表示額外的信息,描述查詢執(zhí)行過程中一些特定的操作。
常見值:
- Using index: 使用覆蓋索引(只從索引中讀取信息,而不是從實際表中讀?。?。
- Using where: 使用 WHERE 子句過濾行。
- Using temporary: 使用臨時表保存中間結(jié)果。
- Using filesort: 需要額外的排序操作(文件排序)。
比如:Using where
示例
為了更好的解釋,我們來看一下示例說明,假設(shè)有一個簡單的表 users,結(jié)構(gòu)如下:
CREATE TABLE users (
id INT PRIMARY KEY,
name VARCHAR(100),
age INT,
city VARCHAR(100)
);
執(zhí)行一個查詢:
EXPLAIN SELECT * FROM users WHERE age > 25;
可能得到的輸出如下:
id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
1 | SIMPLE | users | NULL | ALL | NULL | NULL | NULL | NULL | 1000 | 10.00 | Using where |
解釋:
- id: 查詢的標識符,只有一個簡單查詢,所以 id 是 1。
- select_type: 查詢類型,這里是 SIMPLE,表示簡單查詢。
- table: 查詢涉及的表,這里是 users。
- partitions: 沒有使用分區(qū),所以是 NULL。
- type: 連接類型,這里是 ALL,表示全表掃描。
- possible_keys: 可能使用的索引,這里沒有索引可以使用。
- key: 實際使用的索引,這里沒有使用索引,所以是 NULL。
- key_len: 索引長度,這里沒有使用索引,所以是 NULL。
- ref: 引用的列或常數(shù),這里沒有使用索引,所以是 NULL。
- rows: 估計要掃描的行數(shù),這里估計要掃描 1000 行。
- filtered: 過濾百分比,這里是 10%,表示大約 10% 的行滿足 WHERE 條件。
- Extra: 額外信息,這里是 Using where,表示使用了 WHERE 子句進行過濾。
通過EXPLAIN的結(jié)果,我們可以看到查詢的執(zhí)行計劃,并據(jù)此優(yōu)化查詢。例如,可以考慮在 age 列上添加索引以提高查詢性能。
優(yōu)化建議
根據(jù)EXPLAIN的輸出,可以采取以下優(yōu)化措施:
- 使用合適的索引確保在查詢中使用的列上建立索引。例如,對于 WHERE 子句中的列、JOIN 子句中的連接列、ORDER BY 和 GROUP BY 子句中的列,都應(yīng)考慮建立索引。
- 避免全表掃描:如果 type 列顯示為 ALL,表示全表掃描。應(yīng)該考慮添加索引以避免全表掃描。
- 優(yōu)化連接順序:對于多表連接,優(yōu)化器會選擇最優(yōu)的連接順序??梢酝ㄟ^EXPLAIN查看連接順序,并調(diào)整查詢以優(yōu)化連接順序。
- 使用覆蓋索引如果Extra列顯示為Using index,表示查詢只從索引中讀取數(shù)據(jù),而不需要訪問實際表。可以通過添加合適的索引來實現(xiàn)覆蓋索引。
- 減少返回的行數(shù)使用LIMIT子句限制返回的行數(shù),減少掃描的行數(shù)。
- 避免使用 SELECT盡量避免使用SELECT *,只選擇需要的列以減少數(shù)據(jù)傳輸量。
- 優(yōu)化子查詢對于子查詢,可以考慮使用JOIN或派生表來替代,減少查詢的復(fù)雜度。
總結(jié)
本文,我們詳細地分析了EXPLAIN,它是 MySQL 中用于顯示 SQL 查詢執(zhí)行計劃的關(guān)鍵字。EXPLAIN提供了查詢優(yōu)化器選擇的執(zhí)行路徑,包括表訪問順序、索引使用情況、連接類型和掃描行數(shù)等信息。通過EXPLAIN的輸出,開發(fā)者可以識別性能瓶頸,如全表掃描、索引未使用等,并進行針對性的優(yōu)化,例如添加索引、優(yōu)化連接順序和減少返回行數(shù)等。
因此,在實際開發(fā)中,我們應(yīng)該合理地使用EXPLAIN關(guān)鍵字來幫助我們來優(yōu)化查詢。