MySQL高級知識(八)——ORDER BY優化

前言:在使用order by時,常常出現Using filesort,所以對於此類sql語句需盡力優化,使其儘可能使用Using indexhtml


0.準備

#1.建立test表。算法

drop table if exists test;
create table test(
id int primary key auto_increment,
c1 varchar(10),
c2 varchar(10),
c3 varchar(10),
c4 varchar(10),
c5 varchar(10)
) ENGINE=INNODB default CHARSET=utf8;

insert into test(c1,c2,c3,c4,c5) values('a1','a2','a3','a4','a5');
insert into test(c1,c2,c3,c4,c5) values('b1','b2','b3','b4','b5');
insert into test(c1,c2,c3,c4,c5) values('c1','c2','c3','c4','c5');
insert into test(c1,c2,c3,c4,c5) values('d1','d2','d3','d4','d5');
insert into test(c1,c2,c3,c4,c5) values('e1','e2','e3','e4','e5');

#2.建立索引。sql

1.根據Case分析order by的使用狀況

Case 1:優化

分析:spa

①在c1,c2,c3,c4上建立了索引,直接在c1上使用範圍,致使了索引失效,全表掃描:type=ALL,ref=Null。由於此時c1主要用於排序,並非查詢。3d

②使用c1進行排序,出現了Using filesort指針

③解決方法:使用覆蓋索引code

Case 1.1:視頻

分析:htm

排序時按照索引的順序,因此不會出現Using filesort。

Case 1.2:

分析:

出現了Using filesort。緣由:排序用的c2,與索引的建立順序不一致,對比Case1.1可知,排序時少了c1(帶頭大哥),所以出現Using filesort。

Case 1.3:

分析:

出現了Using filesort。由於排序索引列與索引建立的順序相反,從而產生了重排,也就出現了Using filesort。

Case 2:

分析:

直接使用c2進行排序,出現Using filesort,由於不是從最左列索引開始排序的(沒有帶頭大哥)。

Case 2.1:

分析:

排序使用了索引順序(帶頭大哥在),所以不會出現Using filesort。

Case 2.2:

分析:

雖然排序的字段列與索引順序同樣,且order by默認升序,這裏c2 desc變成了降序,致使與索引的排序方式不一樣,從而產生Using filesort。

總結:

①MySQL支持兩種方式的排序filesortindex,Using index是指MySQL掃描索引自己完成排序。index效率高,filesort效率低。

②order by知足兩種狀況會使用Using index。

#1.order by語句使用索引最左前列

#2.使用where子句與order by子句條件列組合知足索引最左前列。

③儘可能在索引列上完成排序,遵循索引創建(索引建立的順序)時的最佳左前綴法則。

④若是order by的條件不在索引列上,就會產生Using filesort。

#1.filesort有兩種排序算法:雙路排序單路排序

雙路排序:在MySQL4.1以前使用雙路排序,就是兩次磁盤掃描,獲得最終數據。讀取行指針和order by列,對他們進行排序,而後掃描已經排好序的列表,按照列表中的值從新從列表中讀取對應的數據輸出。即從磁盤讀取排序字段,在buffer進行排序,再從磁盤取其餘字段

若是使用雙路排序,取一批數據要對磁盤進行兩次掃描,衆所周知,I/O操做是很耗時的,所以在MySQL4.1之後,出現了改進的算法:單路排序。

單路排序:從磁盤中查詢所需的列,按照order by列在buffer中對它們進行排序,而後掃描排序後的列表進行輸出。它的效率更高一些,避免了第二次讀取數據,而且把隨機I/O變成了順序I/O,可是會使用更多的空間,由於它把每一行都保存在內存中了。

#2.單路排序出現的問題。

當讀取數據超過sort_buffer的容量時,就會致使屢次讀取數據,並建立臨時表,最後多路合併,產生屢次I/O,反而增長其I/O運算。

解決方式:

a.增長sort_buffer_size參數的設置。

b.增大max_length_for_sort_data參數的設置。

⑤提高order by速度的方式:

#1.在使用order by時,不要用select *,只查詢所需的字段

由於當查詢字段過多時,會致使sort_buffer不夠,從而使用多路排序或進行屢次I/O操做。

#2.嘗試提升sort_buffer_size

#3.嘗試提升max_length_for_sort_data

⑥附上一張從視頻中截取出來的總結圖。

⑦group by與order by很相似,其實質是先排序後分組,遵守索引建立順序的最佳左前綴法則。當沒法使用索引列的時候,也要對sort_buffer_sizemax_length_for_sort_data參數進行調整。注意where高於having,能寫在where中的限定條件就不要去having限定了。


by Shawn Chen,2018.6.26日,上午。


相關內容

MySQL高級知識系列目錄

相關文章
相關標籤/搜索