MySQL 中有兩種排序方式:
1.經過有序索引掃描直接返回有序數據,這種方式在使用explain分析查詢的時候顯示爲using index,
不須要額外的排序,操做效率較高。mysql
mysql> explain select start_time from warning_repaired order by start_time desc\G; *************************** 1. row *************************** id: 1 select_type: SIMPLE table: warning_repaired type: index possible_keys: NULL key: start_time key_len: 5 ref: NULL rows: 499471 Extra: Using index 1 row in set (0.00 sec)
2.經過對返回數據進行排序,也就是一般所說的filesort排序,全部不是經過索引直接返回排序結果的排序
都叫filesort排序。 filesort並不表明經過磁盤文件進行排序,而只是進行了一個排序操做,至於排序操做
是否使用了磁盤文件或者臨時表等,則取決於MySQL服務器對排序參數的設置和須要排序數據的大小。
算法
mysql> explain select * from warning_repaired order by start_time desc\G; *************************** 1. row *************************** id: 1 select_type: SIMPLE table: warning_repaired type: ALL possible_keys: NULL key: NULL key_len: NULL ref: NULL rows: 499471 Extra: Using filesort 1 row in set (0.00 sec)
Filesort是經過相應的排序算法,將取得的數據在sort_buffer_size系統變量設置的內存排序區中進行排序,
若是內存裝載不下,它就會將磁盤上的數據進行分塊,再對各個數據進行排序,而後將各個塊合併成有序的
結果集。sort_buffer_size 設置的排序區是每一個線程獨佔的,因此同一個時刻,MySQL 中存在多個
sort buffer 排序區。
瞭解了MySQL 排序方式,優化的目標就清楚了:儘可能減小額外的排序,經過索引直接返回有序數據。
Where 條件和ORDER BY使用相同的索引,而且ORDER BY 的順序和索引順序相同, 而且ORDER BY的字段都是
升序或者都是降序。不然確定須要額外的排序操做,這樣就會出現Filesort.sql
mysql> explain select domain_moid, start_time from warning_repaired order by domain_moid desc\G; *************************** 1. row *************************** id: 1 select_type: SIMPLE table: warning_repaired type: ALL possible_keys: NULL key: NULL key_len: NULL ref: NULL rows: 499471 Extra: Using filesort 1 row in set (0.00 sec) ERROR: No query specified mysql> alter table warning_repaired add index domain_moid_start_time(domain_moid, start_time); Query OK, 0 rows affected (8.32 sec) Records: 0 Duplicates: 0 Warnings: 0 mysql> explain select domain_moid, start_time from warning_repaired order by domain_moid desc\G; *************************** 1. row *************************** id: 1 select_type: SIMPLE table: warning_repaired type: index possible_keys: NULL key: domain_moid_start_time key_len: 115 ref: NULL rows: 499471 Extra: Using index 1 row in set (0.00 sec)
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》dom
參考文章:
性能
http://my.oschina.net/wojibuzhu/blog/118035學習