MySQL語句定位性能問題-explain
1.執行計劃
語法:explain select....
使用extended可以在原來查詢計劃上提供一些優化的信息
語法:explain extended select ....
,然後通過show warnings
來查看相應的優化信息
,測試時發現一個警告,含義EXTENDED將被移除[本地環境mysql5.7]
嘗試不使用EXTENDED
參數,執行show warning
明顯,發現確實是可以使用的並消除了這個警告
2. 執行計劃包含的信息
雖然不同版本的存儲引擎執行計劃不完全相同,但基本信息一致
id: 1
select_type: SIMPLE
table: student
partitions: NULL
type: ALL
ossible_keys: NULL
key: NULL
key_len: NULL
ref: NULL
rows: 2
filtered: 100.00
Extra: NULL
下面進行解釋:
id:由一組數字組成,表示子查詢執行的順序。id相同執行順序自上而下
explain SELECT
i.cust_id AS '客戶ID',
i.cust_name AS '客戶姓名',
IF (l.cust_lmt < '1000',1000, l.cust_lmt) AS '額度'
FROM
cust_inf i
JOIN cust_lmt l ON i.cust_id = l.cust_id ;
id不同,id越大優先級越高,越先被執行
explain SELECT * FROM student union SELECT * FROM student ;
id爲null時表示是一個結果集,不需要使用他查詢,常出現包含union等查詢語句中
select_type
每個子查詢的查詢類型,常見如下表
select_type | description |
---|---|
SIMPLE | 不包含任何子查詢或union等查詢 |
PRIMARY | 包含子查詢,最外層查詢顯示爲PRIMARY |
SUBQUERY | 在select或where子句中 |
DERIVED | from字句中包含的查詢 |
UNION | 出現在union後的查詢語句中 |
UNION RESULT | 從UNION中獲取結果集 |
table
查詢涉及到的數據表
如果查詢使用別名,就顯示別名,如果不涉及對數據表的操作,顯示爲null,如果是尖括號括起來的就標識這個是臨時表,後邊的N就是執行計劃中的id,表示結果
來自於這個查詢產生。如果是尖括號括來<union M,N>,與類似,也是一個臨時表,標識這個結果來自於union查詢的id爲M,N的結果集。
type
訪問類型:
- ALL 掃描全表數據
- index 遍歷索引
- range 索引範圍內查找
- index_subquery在子查詢中使用ref
- unique_subquery在子查詢中使用eq_ref
- ref_or_null 對Null進行優化的ref
- fulltext 使用全文索引
- ref 使用非唯一索引查找數據
- eq_ref 在join查詢中使用PRIMARY KEY or UNIQUE NOT NULL索引關聯
- const使用主鍵或者唯一索引,且匹配結果只有一條記錄
- system const鏈接類型的特例,查詢的表爲系統表
性能從好到差依次爲:system,const,eq_ref,ref,fulltext,ref_or_null,unique_subquery,index_subquery,range,index_merge,index
,ALL,除了ALL之外,其他type類型都可以使用到索引,除了index_merge之外,其他的type類型只可以用到一個索引。
所以通過執行查詢計劃查下某張表的查詢type爲ALL,可以考慮添加索引,或者更換查詢方式,使用索引進行查詢。
possible_keys
可能使用的索引,注意不一定會使用。查詢涉及到的字段上若存在索引,則該索引將被列出來,當該列爲NULL時就要考慮當前SQL是否需要優化了。
key
顯示MySQL在查詢中使用的索引,若沒有引用索引,顯示爲NULL
提示:查詢中若使用了覆蓋索引(覆蓋索引:索引的數據覆蓋了需要查詢的所有數據),則該列僅出現在key列表中
select_type爲index_merge時,這裏可能出現兩個以上的索引,其他的select_type這裏只會出現一個。
key_length
索引長度char()、varchar()索引長度的計算公式
(Character Set:utf8mb4=4,utf8=3,gbk=2,latin1=1) * 列長度 + 1(允許null) + 2(變長列)
其他類型索引長度的計算公式:
CREATE TABLE `student` (
`id` int(11) unsigned NOT NULL AUTO_INCREMENT,
`name` varchar(128) NOT NULL DEFAULT '',
`age` int(11),
PRIMARY KEY (`id`),
UNIQUE KEY `idx` (`name`),
KEY `idx_age` (`age`)
) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8mb4;
name索引長度爲:編碼爲utf8mb4,列長爲128,不允許爲NULL,字段類型爲varchar(128)。key_length=128*4+0+2=514;
同理,age索引長度:int類型佔4位,允許爲null,索引長度爲5。
ref
表示上述表的連接匹配條件,即那些類或常量被用於查找索引列的值
如果是使用常數等值查詢,這裏會顯示const,如果是連接查詢,被驅動表的執行計劃這類會顯示驅動表的關聯字段,如果是條件使用了表達式或者函數,或者條件列發生了內部隱式轉換,這裏可能顯示爲func
rows
返回估算的結果集數目,注意這並不是一個準確值。
extra
extra的信息非常豐富,常見的有:
Using index使用覆蓋索引
Using where使用了where子句過濾結果集
Using filesort使用文件排序,使用非索引列進行排序時出現,非常消耗性能,儘量優化。
Using temporary使用了臨時表
3.一些優化建議
1.SQL語句不要寫的太複雜,儘量簡單,不要嵌套太多層
2.使用“臨時表”緩存查詢結果
3.使用like要注意是否會導致全表掃描
例如:SELECT * FROM table where username like ‘%peiqi%’;
關鍵詞前面有%會導致全表掃描
4.儘量避免使用!=或<>操作符
where語句中使用!=或者<>,引擎將放棄使用索引進而全表掃描
5.儘量避免使用or來連接查詢條件
在where子句中使用or來連接查詢條件,引擎將放棄索引進而全表掃描
可以使用
select id from t where num=‘10’
union all
select id from t where num=‘20’
替代
select id from t where num=‘10’ or num =‘20’
6.儘量避免使用in和not in
在where子句中使用in和not in,搜索引擎可能會放棄索引而進行全表掃描
可以使用
select id from t where num between 10 and 20;
替換
select id from where num in (10,20);
7. 可以考慮強制查詢使用索引
select * from table force index(PRI) limit 2;(強制使用主鍵)
select* from table force index(hollis_index) limit 2;(強制使用索引hollis_index)
select * from table force index(PRI,hollis_index) limit 2;(強制使用索引PRI和hollis_index)
8.儘量避免使用表達式、函數等操作作爲查詢條件
9.儘量避免大事務操作,提高系統併發能力
10.儘量避免使用遊標
11.任何地方都不要使用select* from t,使用具體字段替代*,不返回任何用不到的字段
12.,儘可能使用varchar和nvarchar替代char和nchar
13.儘量使用數字型字段,如果只含數字信息的字段被設計成字符型,鄭輝降低查詢和連接的性能,並且會增加存儲開銷。
14.索引並不是越多越好,索引可以提高select的查詢效率,但是同時也會降低insert和select的效率
15.並不是所有的索引都有效,SQL是根據表中的數據來進行查詢優化的,當索引列有大量的重複時,SQl查詢可能不會使用索引.