mysql 參數調優(14)之優化filesort sort_buffer_size、innodb_sort_buffer_size

SHOW VARIABLES LIKE '%sort_buffer_size%'
SHOW VARIABLES LIKE '%innodb_sort_buffer_size%'
SHOW VARIABLES LIKE '%read_rnd_buffer_size%'

有時我們使用EXPLAIN工具,可以看到查詢計劃的輸出中的Extra列有filesort。filesort往往意味着你沒有利用到索引進行排序。filesort的字面意思可能會導致混淆,它和文件排序沒有任何關係,可以理解爲不能利用索引實現排序。

觸發file sort的時機
1、排序一個帶JOIN(連接)的查詢,如果ORDERBY子句參考的是JOIN順序裏的第一張表的列且不能利用索引進行排序,那 麼MySQL會對這個表進行文件排序(filesort),EXPLAIN輸出中的Extra列就有filesort。
2、如果排序的列來自於其他的表,且需要臨時文件來幫助排序,那麼EXPLAIN輸出的Extra列就有“Using temporary;Using filesort”字樣。
3、對於MySQL 5.1,如果有LIMIT子 句,那麼是在filesort之後執行LIMIT的,這樣做效率可能會很差,因爲需要排序過多的記錄。

兩種filesort算法
MySQL有兩種filesort算法:two-pass和single-pass。

(1)two-pass
這是舊的算法。列長度之和超過max_length_for_sort_data字節時就使用這個算法,其原理是:先按照WHERE 篩選條件讀取數據行,並存儲每行的排序字段行指針排序緩衝(sort buffer)。如果排序緩衝大小不夠,就在內存中運行一個快速排序 (quick sort)操作,把排序結果存儲到一個臨時文件裏,用一個指針指向這個已經排序好了的塊。然後繼續讀取數據,直到所有行都讀取完畢爲止。這是第一次讀取記錄。 然後合併如上的臨時文件,進行排序。 然後依據排序結果再去讀取所需要的數據,讀入行緩衝(rowbuffer,由read_rnd_buffer_size參數設定其大小)。這是第二次 讀取記錄。 以上第一次讀取記錄時,可以按照索引排序或表掃描,可以做到順序讀取。但第二次讀取記錄時,雖然排序字段是有序的,行緩衝裏存儲的行指針是有序的,但所指向的物理記錄需要隨機讀,所以這個算法可能會帶來很多隨機讀,從而導致效率不佳。
優點: 排序的數據量較小,一般在內存中即可完成。
缺點: 需要讀取記錄兩次,第二次根據排序之後的指針進行讀取時,可能會產生許多隨機I/O,成本可能會比較高。

(2)single-pass

這是新的filesort排序算法。MySQL一般使用這種算法。其原理是:按篩選條件,一次性把SQL中涉及的字段全部讀入排序緩衝(sort buffer)中,然後依據排序字段進行排序,如果排序緩衝不夠,則會將臨時排序結果寫入到一個臨時文件中,最後合併臨時排序文件,直接返回已經排序好的結果集。
優點: 不需要讀取記錄兩次,相對於two-pass,可以減少I/O開銷。
缺點: 由於要讀入所有字段,排序緩衝可能不夠,需要額外的臨時文件協助進行排序,導致增加額外的I/O成本。(可以充分利用空閒內存進行排序優化)。會吹出現 高磁盤活動和低CPU活動的組合

參數調整優化file sort

爲了提高排序速度,請檢查您是否可以讓MySQL使用索引,而不是額外的排序階段。如果不可能,請嘗試以下策略:

1、調整max_length_for_sort_data以控制何時使用two-pass 或 single-pass
如果各列長度之和(包括選擇列、排序列)超過了max_length_for_sort_data字節,那麼就使用two- pass算法。如果排序BLOB、TEXT字段,使用的也是two-pass算法,那麼這個值設置得太高會更加容易地使用single-pass。導致系統I/O上升,CPU下降,建議不要將max_length_for_sort_data設置得太高。

對於不使用 two-pass 的慢速ORDER BY查詢,請嘗試將max_length_for_sort_data系統變量降低到適合觸發 two-pass 的值。(將該變量的值設置得太高的一個症狀是高磁盤活動和低CPU活動的組合。)

SHOW VARIABLES LIKE '%max_length_for_sort_data%' -- 1024Bytes 1KBB

2、調整max_sort_length,優化two-pass讀取的BLOB、TEXT大字段
如果排序BLOB、TEXT字段,則僅排序前max_sort_length個字節。請考慮存儲在排序緩衝區中的列值的大小受max_sort_length系統變量值的影響。例如,如果元組存儲長字符串列的值,並且您增加了max_sort_length的值,則排序緩衝區元組的大小也會增加,並且可能需要您增加sort_buffer_size。對於作爲字符串表達式結果計算的列值(例如調用字符串值函數的列值),文件排序算法無法判斷表達式值的最大長度,因此它必須爲每個元組分配max_sort_length字節。

SHOW VARIABLES LIKE '%max_sort_length%' -- 1024Bytes 1KB

3、加大sort_buffer_size優化single-pass
一般情況下使用默認的single-pass新算法即可。可以考慮加大sort_buffer_size以減少磁盤I/O。 需要留意的是字段長度之和不要超過max_length_for_sort_data,只查詢所需要的列,注意列的類型、長度(因爲超過max_length_for_sort_data就會去使用舊排序算法two-pass )。MySQL目前讀取和計算列的長度是按照定義的最大的度進行的,所以在設計表結構的時候,不要將VARCHAR類型的字段設置得過大,雖然對於VARCHAR類型來說,在物理磁盤中的實際存儲可以做到緊湊,但在排序的時候,是會分配最大定義的長度的,有時排序階段所產生的臨時文件甚至比原始表還要大。

增加sort_buffer_size變量值。理想情況下,該值應該足夠大,以使整個結果集適合排序緩衝區(避免寫入磁盤和合並過程),但至少該值必須足夠大,以容納15個元組。(最多可合併15個臨時磁盤文件,並且每個文件在內存中必須有至少一個元組的空間。)

SHOW VARIABLES LIKE '%sort_buffer_size%' -- 262144字節 256KB

4、加大read_rnd_buffer_size優化 two-pass
對於two-pass舊算法,可以考慮增大read_rnd_buffer_size,但由於這個全局變量是對所有連接都生效的,因此建議只在會話級別進行設置,以加速一些特殊的大操作。增加read_rnd_buffer_size變量值,以便一次讀取更多行。

SHOW VARIABLES LIKE '%read_rnd_buffer_size%' -- 262144Bytes 256KB

5、要監視合併過程的次數(合併臨時文件),請檢查排序合併過程狀態變量。

6、將tmpdir系統變量更改爲指向具有大量可用空間的專用文件系統。變量值可以列出以循環方式使用的幾個路徑;您可以使用此功能將負載分散到幾個目錄中。在Unix上用冒號(:)和分號(;)分隔路徑。)在Windows上。路徑應該命名位於不同物理磁盤上的文件系統中的目錄,而不是同一磁盤上的不同分區。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章