1. 程式人生 > >資料庫原理:MySQL檔案排序演算法與引數

資料庫原理:MySQL檔案排序演算法與引數

對於不能利用索引避免排序的SQL,資料庫不得不自己實現排序功能以滿足使用者需求,此時SQL的執行計劃中會出現“Using filesort”,
這裡需要注意的是filesort並不意味著就是檔案排序,其實也有可能是記憶體排序,這個主要由sort_buffer_size引數與結果集大小確定。

假設表結構和SQL語句如下:
CREATE TABLE t1 (
id INT,
col1 VARCHAR (64),
col2 VARCHAR (64),
col3 VARCHAR (64),
PRIMARY KEY (id),
KEY (col1, col2)
);
SELECT col1,col2,col3 FROM t1 WHERE col1>100 ORDER BY col2;

a.常規排序,雙路排序
(1).從表t1中獲取滿足WHERE條件的記錄
(2).對於每條記錄,將記錄的主鍵+排序鍵(id,col2)取出放入sort buffer
(3).如果sort buffer可以存放所有滿足條件的(id,col2)對,則進行排序;否則sort buffer滿後,進行排序並寫到臨時檔案中。(排序算
法採用的是快速排序演算法)
(4).若排序中產生了臨時檔案,需要利用歸併排序演算法,保證臨時檔案中記錄是有序的
(5).迴圈執行上述過程,直到所有滿足條件的記錄全部參與排序
(6).掃描排好序的(id,col2)對,即sort buffer,並利用主鍵id去取SELECT需要返回的其他列(col1,col2,col3)
(7).將獲取的結果集返回給使用者。

從上述流程來看,是否使用檔案排序主要看sort buffer是否能容下需要排序的(id,col2)的結果集,這個buffer的大小由
sort_buffer_size引數控制。此外一次排序還需要兩次IO,一次是取排序欄位(id,col2)到sort buffer中,第二次是通過上面取出的主鍵
id再來取其他所需要返回列(col1,col2,col3),由於返回的結果集是按col2排序,因此id是亂序的,通過亂序的id取(col1,col2,col3)時
會產生大量的隨機IO。對於第二次IO取MySQL本身會優化,即在取之前先將主鍵id排序,並放入快取區,這個快取區大小由引數
read_rnd_buffer_size控制,然後有序去取記錄,將隨機IO轉為順序IO。

b.優化排序,單路排序
常規排序方式除了排序本身,還需要額外兩次IO。優化排序方式相對於常規排序,減少了第二次IO。主要區別在於,一次性取出SQL中出現
的所有欄位放入sort buffer中而不是隻取排序需要的欄位(id,col2)。由於sort buffer中包含了查詢需要的所有欄位,因此排序完成後可
以直接返回,無需二次取資料。這種方式的代價在於,同樣大小的sort buffer,能存放的(col1,col2,col3)數目要小於(id,col2),如果
sort buffer不夠大,可能導致需要寫臨時檔案,造成額外的IO。當然MySQL提供了引數max_length_for_sort_data,只有當排序SQL裡出現
的所有欄位小於max_length_for_sort_data時,才能利用優化排序方式,否則只能用常規排序方式。