Using temporary
Using temporary
表示由於排序沒有走索引、使用union
、子查詢連接查詢、使用某些視圖等原因(詳見https://dev.mysql.com/doc/refman/5.6/en/internal-temporary-tables.html),因此創建了一個內部臨時表。注意這里的臨時表可能是內存上的臨時表,也有可能是硬盤上的臨時表,理所當然基於內存的臨時表的時間消耗肯定要比基於硬盤的臨時表的實際消耗小。
查看sql執行時使用的是內存臨時表還是硬盤臨時表,需要使用如下命令:
mysql> show global status like '%tmp%'; +-------------------------+-------+ | Variable_name | Value | +-------------------------+-------+ | Created_tmp_disk_tables | 0 | | Created_tmp_files | 5 | | Created_tmp_tables | 11 | +-------------------------+-------+
Created_tmp_tables表示mysql創建的內部臨時表的總數(包括內存臨時表和硬盤臨時表);Created_tmp_disk_tables表示mysql創建的硬盤臨時表的總數。
當mysql需要創建臨時表時,選擇內存臨時表還是硬盤臨時表取決於參數tmp_table_size和max_heap_table_size,內存臨時表的最大容量為tmp_table_size
和max_heap_table_size
值的最小值,當所需臨時表的容量大於兩者的最小值時,mysql就會使用硬盤臨時表存放數據。
用戶可以在mysql的配置文件里修改該兩個參數的值,兩者的默認值均為16M。
tmp_table_size = 16M
max_heap_table_size = 16M
查看tmp_table_size
和max_heap_table_size
值:
mysql> show global variables like 'max_heap_table_size'; +---------------------+----------+ | Variable_name | Value | +---------------------+----------+ | max_heap_table_size | 16777216 | +---------------------+----------+ mysql> show global variables like 'tmp_table_size'; +----------------+----------+ | Variable_name | Value | +----------------+----------+ | tmp_table_size | 16777216 | +----------------+----------+ 如果ORDER BY或GROUP BY中的字段都來自其他的表而非連接順序中的第一個表的話,就會創建一個臨時表了。
Using filesort
如果問Using filesort
是什么意思,大多數人應該會回答“基於硬盤的排序”或者“數據太多不適合內存,所以在硬盤上排序”。然而這些解釋是錯誤的。
Using filesort
僅僅表示沒有使用索引的排序,事實上filesort
這個名字很糟糕,並不意味着在硬盤上排序,filesort
與文件無關。因此消除Using filesort
的方法就是讓查詢sql的排序走索引。
filesort
使用的算法是QuickSort
,即對需要排序的記錄生成元數據進行分塊排序,然后再使用mergesort方法合並塊。其中filesort
可以使用的內存空間大小為參數sort_buffer_size的值,默認為2M。當排序記錄太多sort_buffer_size
不夠用時,mysql會使用臨時文件來存放各個分塊,然后各個分塊排序后再多次合並分塊最終全局完成排序。
mysql> show global variables like 'sort_buffer_size'; +------------------+--------+ | Variable_name | Value | +------------------+--------+ | sort_buffer_size | 262144 | +------------------+--------+
Sort_merge_passes表示filesort
執行過的文件分塊合並次數的總和,如果該值比較大,建議增大sort_buffer_size
的值。
mysql> show global status like '%sort%'; +-------------------+---------+ | Variable_name | Value | +-------------------+---------+ | Sort_merge_passes | 226 | | Sort_range | 0 | | Sort_rows | 1384911 | | Sort_scan | 6 | +-------------------+---------+
filesort排序方式
filesort
使用的排序方法有兩種:
第一種方法是對需要排序的記錄生成<sort_key,rowid>
的元數據進行排序,該元數據僅包含排序字段和rowid。排序完成后只有按字段排序的rowid,因此還需要通過rowid進行回表操作獲取所需要的列的值,可能會導致大量的隨機IO讀消耗;
第二種方法是是對需要排序的記錄生成<sort_key,additional_fields>
的元數據,該元數據包含排序字段和需要返回的所有列。排序完后不需要回表,但是元數據要比第一種方法長得多,需要更多的空間用於排序。
參數max_length_for_sort_data字段用於控制filesort
使用的排序方法,當所有需要排序記錄的字段數量總和小於max_length_for_sort_data
時使用第二種算法,否則會用第一種算法。該值的默認值為1024。
mysql> show global variables like 'max_length_for_sort_data'; +--------------------------+-------+ | Variable_name | Value | +--------------------------+-------+ | max_length_for_sort_data | 1024 | +--------------------------+-------+ mysql> set global max_length_for_sort_data = 1024;
在排序的語句中都出現了Using filesort,字面意思可能會被理解為:使用文件進行排序或中文件中進行排序。實際上這是不正確的,這是一個讓人產生誤解的詞語。
當我們試圖對一個沒有索引的字段進行排序時,就是filesoft。它跟文件沒有任何關系,實際上是內部的一個快速排序。