mysql 優化order by
MySQL 中有兩種排序方式:
1.通過有序索引掃描直接返回有序數據,這種方式在使用explain分析查詢的時候顯示為using index,
不需要額外的排序,操作效率較高。
mysql> explain select count(id) from warning_repaired\G; *************************** 1. row *************************** id: 1 select_type: SIMPLE table: warning_repaired type: index possible_keys: NULL key: id key_len: 4 ref: NULL rows: 499471 Extra: Using index 1 row in set (0.00 sec)
2.通過對返回數據進行排序,也就是通常所說的filesort排序,所有不是通過索引直接返回排序結果的排序
都叫filesort排序。 filesort并不代表通過磁盤文件進行排序,而只是進行了一個排序操作,至于排序操作
是否使用了磁盤文件或者臨時表等,則取決于MySQL服務器對排序參數的設置和需要排序數據的大小。
Filesort是通過相應的排序算法,將取得的數據在sort_buffer_size系統變量設置的內存排序區中進行排序,
如果內存裝載不下,它就會將磁盤上的數據進行分塊,再對各個數據進行排序,然后將各個塊合并成有序的
結果集。sort_buffer_size 設置的排序區是每個線程獨占的,所以同一個時刻,MySQL 中存在多個
sort buffer 排序區。
了解了MySQL 排序方式,優化的目標就清楚了:盡量減少額外的排序,通過索引直接返回有序數據。
Where 條件和ORDER BY使用相同的索引,并且ORDER BY 的順序和索引順序相同, 并且ORDER BY的字段都是
升序或者都是降序。否則肯定需要額外的排序操作,這樣就會出現Filesort.
Filesort的優化:
通過創建合適的索引能夠減少filesort的出現,但是某些情況下,條件限制不能讓Filesort消失,那就需要
想辦法加快filesort的操作。對于filesort, MySQL 有兩種排序算法。
1.兩次掃描算法(two passes): 首先根據條件取出排序字段和行指針信息,之后在排序區Sort buffer 中排序,如果排序區sort bufer 不夠,則在臨時表Temporary Table中存儲排序結果,完成排序后,根據行指針
回表讀取數據。該算法是在mysql4.1之前采用的算法,需要兩次訪問數據,第一次獲取排序字段和行指針信息。
第二次根據行指針獲取記錄,尤其是第二次讀取操作可能導致大量隨機I/O;優點是排序的時候內存開銷小。
2. 一次掃描算法(single Pass):一次性取出滿足條件的行的所有字段,然后在排序區sort buffer 中排序后直接
輸出結果集。排序的時候內存開銷大比較大。但是排序效率比兩次掃描算法要高。
MySQL 通過比較系統變量max_length_for_sort_data 的大小和Query 語句取出的字段總大小來判斷使用
哪種算法。如果max_length_for_sort_data 更大,那么使用第二種優化之后的算法,否則使用第一種算法。
適當的加大系統變量max_length_for_sort_data的值,能夠讓MySQL選擇更優化的Filesort排序算法。但是,如果
max_length_for_sort_data設置過大,就會造成CPU利用率過低和磁盤I/O過高,CPU和I/O利用平衡就足夠了。
適當加大sort_buffer_size排序區,盡量讓排序在內存中完成,而不是通過創建臨時表放在文件中進行;
當然也不能無限加大sort_buffer_size排序區,因為sort_buffer_size參數是每個線程獨占的。設置過大,
會導致服務器SWAP嚴重,要考慮數據庫活動連接數和服務器內存的大小適當設置排序區。
盡量只使用必要的字段,SELECT 具體的字段名稱,而不是SELECT * 選擇所有字段,
這樣可以減少排序區的使用,提高SQL 性能。
學習自《深入淺出mysql》