資料庫原理:MySQL檔案排序演算法與引數
阿新 • • 發佈:2018-12-26
對於不能利用索引避免排序的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時,才能利用優化排序方式,否則只能用常規排序方式。