MySQL 執行計劃說明
上一篇文章“SQL關聯查詢 直接join 和子查詢的區別”中提到了explain,即執行計劃。執行計劃是資料庫引擎的重要一環,今天針對explain結果瞭解下,順便提及幾個有意思的話題,如“回表”、“如何在MySQL中實現rowNum”。
explain結果說明
- select_type
型別 | 說明 |
---|---|
SIMPLE | 簡單SELECT(不使用UNION或子查詢等) |
PRIMARY | 主查詢,即最外面的SELECT |
UNION | UNION中的第二個或後面的SELECT語句 |
DEPENDENT UNION | NION中的第二個或後面的SELECT語句,取決於外面的查詢 |
UNION RESULT | UNION的結果 |
SUBQUERY | 子查詢中的第一個SELECT |
DEPENDENT SUBQUERY | 子查詢中的第一個SELECT,取決於外面的查詢 |
SUBQUERY | 匯出表的SELECT(FROM子句的子查詢) |
-
table
輸出結果集的表名 -
partitions
存在分割槽時,使用到哪些分割槽 - type
連線使用了哪種類別,有無使用索引,是使用Explain命令分析效能瓶頸的關鍵項之一。常見訪問型別如下,按照效能排序,從上到下,從差到好。一般來說,得保證查詢至少達到range級別,最好能達到ref,否則就可能會出現效能問題。
型別 | 值 | 示例說明 |
---|---|---|
ALL | 全表掃描 | 一般是沒有where條件或者where條件沒有使用索引的查詢語句 |
index | 索引全掃描 | 一般是查詢的欄位都有索引的查詢語句 |
range | 索引範圍掃描 | 常用於<、<=、>、>=、between等操作 |
ref | 非唯一索引掃描 | 使用非唯一索引或唯一索引的字首掃描,返回匹配某個單獨值的記錄行 |
eq_ref | 唯一索引掃描 | 類似ref,區別在於使用的索引是唯一索引,對於每個索引鍵值,表中只有一條記錄匹配 |
const,system | 單表最多有一個匹配行 | onst/system出現在根據主鍵primary key或者 唯一索引 unique index 進行的查詢 |
NULL | 不用掃描表或索引 | select 1 from dual |
-
possible_keys
列指出MySQL能使用哪個索引在該表中找到行 -
key
顯示MySQL實際決定使用的鍵(索引)。如果沒有選擇索引,鍵是NULL -
key_len
顯示MySQL決定使用的鍵長度。如果鍵是NULL,則長度為NULL。使用的索引的長度。在不損失精確性的情況下,長度越短越好 -
ref
顯示使用哪個列或常數與key一起從表中選擇行。 -
rows
顯示MySQL認為它執行查詢時必須檢查的行數。 -
filtered
儲存引擎返回的資料在server層過濾後,剩下多少滿足查詢的記錄數量的比例(百分比) - extra
包含MySQL解決查詢的詳細資訊,也是關鍵參考項之一。
extra元素 | 說明 |
---|---|
Distinct | 一旦MYSQL找到了與行相聯合匹配的行,就不再搜尋了 |
Not exists | MYSQL 優化了LEFT JOIN,一旦它找到了匹配LEFT JOIN標準的行,就不再搜尋了 |
Range | checked for each |
Record | 沒有找到理想的索引,因此對於從前面表中來的每一 個行組合,MYSQL檢查使用哪個索引,並用它來從表中返回行。這是使用索引的最慢的連線之一 |
Using filesort | 表示MySQL需額外排序操作, 不能通過索引順序達到排序效果 |
Using index | 表示索引覆蓋,不會回表查詢 |
Using temporary | 通常發生在對不同的列集進行ORDER BY上,而不是GROUP BY上 |
Using where | 表示進行了回表查詢 |
什麼是回表
簡單來說就是資料庫根據索引找到了指定的記錄所在行後,還需要根據rowid再次到資料塊裡取資料的操作。比如這樣的執行計劃,先索引掃描,再通過rowid去取索引中未能提供的資料,即為回表。“回表”一般就是指執行計劃裡顯示的“TABLE ACCESS BY INDEX ROWID”。再例如,雖然只查詢索引裡的列,但是需要回表過濾掉其他行。
怎麼避免回表?
將需要的欄位放在索引中去。查詢的時候就能避免回表。但是不要刻意去避免回表,那樣代價太了。也不是將所有的欄位都放在所有中。
回表和MySQL的索引實現有關係,有興趣的朋友可以進一步瞭解B+樹相關原理,參照下面這篇文章“從B樹、B+樹、B*樹談到R 樹”。
MySQL如何獲取rownum
不同於oracle的rownum,mysql不太直接提供這樣的欄位,但是可以用變數的方法新增偽自增序列,語法格式為SELECT @rownum:[email protected]+1 AS rownum, table_name.* FROM (SELECT @rownum:=0) r, table_name ;