天天看點

mysql 查詢優化 exists_Mysql查詢優化order by /exists/group by

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執行計劃

mysql 查詢優化 exists_Mysql查詢優化order by /exists/group by

不會産生filesort

mysql 查詢優化 exists_Mysql查詢優化order by /exists/group by

不會産生filesort,因為order by 排序是按照建立索引順序排列的且覆寫全索引

mysql 查詢優化 exists_Mysql查詢優化order by /exists/group by

# 會産生 原因是age 為範圍排序,導緻後面索引birth失效。最後使用filesort

mysql 查詢優化 exists_Mysql查詢優化order by /exists/group by

會使用到filesort order by 後面索引字段颠倒順序

mysql 查詢優化 exists_Mysql查詢優化order by /exists/group by

order by 後面沒有遵照最左字首

mysql 查詢優化 exists_Mysql查詢優化order by /exists/group by

會使用filesort,與上例一樣。order by 後面沒有遵照最左字首

mysql 查詢優化 exists_Mysql查詢優化order by /exists/group by

不會使用filesort

mysql 查詢優化 exists_Mysql查詢優化order by /exists/group by

會使用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 對于排序來說,多個相等條件也是範圍查詢