mysql 建立materialized檢視_MySQL執行計劃
MySQL執行計劃
我們經常使用 MySQL 的執行計劃來檢視 SQL 語句的執行效率,接下來分析執行計劃的各個顯示內容。
EXPLAIN SELECT ( SELECT t2.NAME FROM tb_dept t2 WHERE t2.id = t1.dept_id ) FROM tb_user t1, tb_user_role t3, tb_role t4 WHERE t1.id=t3.user_id AND t3.role_id = t4.id AND t4.name='開發部'
執行計劃的 id
select 查詢的序列號,標識執行的順序
- id相同,執行順序由上至下
- id不同, 如果是子查詢,id 的序號會遞增,id 值越大優先順序越高,越先被執行
執行計劃的 select_type
- SIMPLE:簡單的 select 查詢,查詢中不包含子查詢或者UNION
- PRIMARY:為複雜查詢建立的首要表(也是最外層的表) 這種型別通常與DERIVED 或者 UNION 混合使用見到
- UNION: 當SELECT 之前的關鍵字為UNION 或 UNION ALL時 會出現UNION 關鍵字
- DEPENDENT UNION: 當子查詢中存在UNION時UNION 後的 select_type 會出現 DEPENDENT UNION 而union 語句的第一行為 DEPENDENT SUBQUERY
- UNION RESULT: 出現在UNION 或UNION ALL語句中 代表把所有結果集聯合起來
- SUBQUERY:出現在複雜非相關子查詢中 ,簡單相關子查詢MySQL會進行改寫
- DEPENDENT SUBQUERY: 出現在相關子查詢中而非相關子查詢MySQL可以進行改寫
- DERIVED: 衍生表當查詢使用內聯檢視時會出現此關鍵字
- MATERIALIZED: 子查詢物化 ,當表出現在非相關子查詢中並且需要進行物化時會出現MATERIALIZED關鍵詞
- UNCACHEABLE SUBQUERY:表示子查詢不可被物化需要逐次執行
- UNCACHEABLE UNION: 子查詢中出現UNION並且不可被快取在UNION 後的 SELECT 語句出現此關鍵詞
執行計劃的 table
查詢涉及到的表。
- 直接顯示錶名或者表的別名
- <union M,N> 由 id 為 M,N 查詢 union 產生的結果
- <subqueryN> 由 id 為 N 查詢產生的結果
執行計劃的 partitions
表分割槽、表建立的時候可以指定通過那個列進行表分割槽。
create table tmp (
id int unsigned not null AUTO_INCREMENT,
name varchar(20),
PRIMARY KEY (id)
)engine = innodb partition by key (id) partitions 5;
執行計劃的 type
訪問型別,SQL 查詢優化中一個很重要的指標,結果值從好到壞依次是:system > const > eq_ref > ref > fulltext > ref_or_null > index_merge > unique_subquery > index_subquery > range > index > ALL
一般常用和需要重點關注的 system > const > eq_ref > ref > range > index > ALL。
- system:系統表,少量資料,不進行磁碟IO,這是 const 型別的特列,平時不會出現,這個也可以忽略不計
- const: PK 或者 unique 上的等值查詢
- eq_ref: PK 或者 unique 上的 join 查詢,等值匹配,對於前表的每一行,後表只有一行命中
- ref: 非唯一索引,等值匹配,可能有多行命中
- range: 索引上的範圍掃描,例如:between、in、>
- index:索引樹掃描, 例如:Innodb 的 count
- ALL: 全表掃描(full table scan)
執行計劃的 possible_keys
查詢過程中有可能用到的索引。(不重要)
執行計劃的 key
實際使用的索引,如果為 NULL ,則沒有使用索引 。
執行計劃的 key_len
key_len 表示索引使用的位元組數,根據這個值就可以判斷索引使用的情況。特別是在組合索引的時候,判斷索引的索引欄位是否都被查詢到。那麼key_len是怎麼計算的呢,計算方法如下:
1. 整數型別,浮點數型別,時間型別的索引長度
NOT NULL = 欄位本身的欄位長度
NULL = 欄位本身的欄位長度+1,因為需要有是否為空的標記,這個標記需要佔用1個位元組
datetime = datetime不存毫秒的情況下是5個位元組,存毫秒的情況下是8個位元組
2.字元型別
varchr(n)變長欄位且允許NULL = n * (utf8=3,gbk=2,latin1=1)+1(NULL)+2
varchr(n)變長欄位且不允許NULL = n * (utf8=3,gbk=2,latin1=1)+2
char(n)固定欄位且允許NULL = n * (utf8=3,gbk=2,latin1=1)+1(NULL)
char(n)固定欄位且不允許NULL = n * (utf8=3,gbk=2,latin1=1)
變長欄位需要額外的2個位元組(VARCHAR值儲存時只儲存需要的字元數,另加一個位元組來記錄長度(如果列宣告的長度超過255,則使用兩個位元組),所以VARCAHR索引長度計算時候要加2),固定長度欄位不需要額外的位元組。
而NULL都需要1個位元組的額外空間,所以索引欄位最好不要為NULL,因為NULL讓統計更加複雜並且需要額外的儲存空間。
複合索引有最左字首的特性,如果複合索引能全部使用上,則是複合索引欄位的索引長度之和,這也可以用來判定複合索引是否部分使用,還是全部使用。下面舉個例子:
DROP TABLE IF EXISTS `users`;
CREATE TABLE `users` (
`id` bigint NOT NULL AUTO_INCREMENT ,
`username` varchar(10) NOT NULL ,
`password` varchar(20) NOT NULL ,
`name` varchar(10) NOT NULL ,
`idCard` char(10) DEFAULT NULL ,
`age` int NOT NULL ,
PRIMARY KEY (`id`) USING BTREE,
KEY `idx_user` (`name`,`idCard`,`age`)
) ENGINE=InnoDB AUTO_INCREMENT=14 DEFAULT CHARSET=utf8;
EXPLAIN SELECT * FROM users WHERE name='admin' AND idcard='1234' AND age = 20;
name
型別為 varchar,長度為10
idcard
型別為 char, 長度為10,可為空
age
型別為 int
字符集型別 utf8
key_len = ( 10 * 3 + 2 ) + (10 * 3 + 1 ) + 4 = 67
執行計劃的 ref
表示上述表的連線匹配條件,即哪些列或常量被用於查詢索引列上的值
執行計劃的 rows
根據表統計資訊或者索引選用情況,大致估算出找到所需的記錄所需要讀取的行數。
執行計劃的 filtered
表示返回結果的行數佔需讀取行數的百分比, filtered 的值越大越好。
執行計劃的 Extra
十分重要的額外資訊。
- Using filesort:MySQL 對資料使用一個外部的檔案內容進行了排序,而不是按照表內的索引進行排序讀取。
- Using temporary:使用臨時表儲存中間結果,也就是說 MySQL 在對查詢結果排序時使用了臨時表,常見於 order by 或 group by。
- Using index:表示 SQL 操作中使用了覆蓋索引(Covering Index),避免了訪問表的資料行,效率高。
- Using index condition:表示 SQL 操作命中了索引,但不是所有的列資料都在索引樹上,還需要訪問實際的行記錄。
- Using where:表示 SQL 操作使用了 where 過濾條件。
- Select tables optimized away:基於索引優化 MIN/MAX 操作或者 MyISAM 儲存引擎優化 COUNT(*) 操作,不必等到執行階段再進行計算,查詢執行計劃生成的階段即可完成優化。
- Using join buffer (Block Nested Loop):表示 SQL 操作使用了關聯查詢或者子查詢,且需要進行巢狀迴圈計算。MySQL執行計劃