order by 子句,盡量使用Index方式排序,避免使用FileSort方式排序。
為了友善示範,先建立一個表并插入資料資料
create table tblA(
id int primary key not null auto_increment,
age int,
birth timestamp not null
);
insert into tblA(age,birth)values(22,now());
insert into tblA(age,birth)values(23,now());
insert into tblA(age,birth)values(24,now());
...
# 建立索引
create index idx_A_ageBirth on tblA(age,birth);
首先我們看幾個order by執行計劃

不會産生filesort
不會産生filesort,因為order by 排序是按照建立索引順序排列的且覆寫全索引
# 會産生 原因是age 為範圍排序,導緻後面索引birth失效。最後使用filesort
會使用到filesort order by 後面索引字段颠倒順序
order by 後面沒有遵照最左字首
會使用filesort,與上例一樣。order by 後面沒有遵照最左字首
不會使用filesort
會使用filesort,又升序又降序,導緻MySQL無法了解
MySQL支援兩種方式排序,FileSort和Index,當然Index效率高,它指MySQL掃描索引本身完成的排序,而FileSort方式效率比較低。
由上面例子,不難看出規律, order by 滿足一下2種情況,會使用Index方式排序:
order by 語句也遵循最左字首原則
使用where子句與order by子句條件列組合滿足索引最左前列
索引我們有必要盡可能在索引列上完成排序操作,遵照索引建在最左字首。如果不在索引列上,則會使用filesort,而filesort又有2種算法,mysql就要啟動雙路排序和單路排序、
雙路排序?單路排序?又是什麼鬼?
1.雙路排序:
MySQL4.1之前使用雙路排序,字面意思就是兩次掃描硬碟,最終得到資料,
讀取行指針和orderby列,對他們進行排序,然後掃描已經排序好的清單,
按照清單中的值重新從清單中讀取對應的資料。
簡單了解從磁盤取排序字段,在buffer進行排序,再從磁盤取其他字段。這樣從磁盤取出一批資料,要對磁盤進行2次掃描,衆所周知,IO是很耗時的,是以再mysql4.1之後,出現第二種改進算法,就是單路排序。
2.單路排序:
從磁盤讀取查詢需要的所有列,按照order by列再buffer對它們進行排序,
然後掃描排序後的清單進行輸出,它的效率更快一些,避免了第二次讀取資料,
并且把随機IO變成順序IO,但是它會使用更多的空間,因為它把每一行都儲存
在記憶體中。
但是單路排序又存在着問題:
在sort_buffer中,單路操作要比雙路操作占用更多空間,因為單路操作是把所有字段取出,
是以有可能取出的資料總大小超出了sort_buffer的容量,導緻每次隻能取sort_buffer容量大小的資料,進行排序(建立tmp檔案,多路合并),排完再取sort_buffer容量大小,再排序... 進而多次I/O操作
本想省一次I/O操作,反而導緻了大量的I/O操作,反而得不償失。
那麼如何解決或是如何優化?
1. SQL資料庫配置檔案優化:
- 增大sort_buffer_size 參數的設定:不管哪種算法,提高這個參數都會提高效率,
當然,要根據系統的能力去提高,因為這個參數是針對每個程序的。
- 增大max_length_for_sort_data 參數的設定:提高這個參數,會增加用改進算法
的機率,但是如果設定太高,資料總容量超出sort_buffer_size的機率就增大,明顯
症狀是高的磁盤I/O活動和低的處理器使用率。
2.不要用 select *
- 當Query 字段大小總和小于max_length_for_sort_data 而且排序字段不是TEXT或BLOB類型,會用改進後的算法---單路排序,否則用老算法---雙路排序
- 兩種算法的資料都有可能超出sort_buffer的容量,超出之後,會建立tmp檔案進行合并排序,導緻多次I/O,但是用單路排序算法的風險會更大一些,是以要提高sort_buffer_size
order by 小總結:
當我們索引 key a_b_c(a,b,c)
Mysql兩種排序方式:檔案排序Using filesort/有序索引Using index
order by 能使用索引最左字首情況:
order by a
order by a,b
order by a,b,c
order by a DESC,b DESC,c DESC
如果有where如果where使用索引的最左字首定義為常量,則order by 能使用索引:
where a=const order b,c
where a=const and b=const order by c
where a=const order by b,c
where a=const and b>const order by b,c
不能使用索引進行排序情況:
order by a ASC,b DESC,c DESC 排序不一緻
where g=const order by b,c 丢失a索引
where a=const order by c 丢失b索引
where a=const order by a,d d不是索引的一部分
where a in (...) order by b,c 對于排序來說,多個相等條件也是範圍查詢