mysql order by是怎麼工作的?

小二郎**發表於2019-05-20

假設我們要查詢一個市民表中城市=杭州的所有人的名字,並且按照名字排序

CREATE TABLE `t` (
  `id` int(11) NOT NULL,
  `city` varchar(16) NOT NULL,
  `name` varchar(16) NOT NULL,
  `age` int(11) NOT NULL,
  `addr` varchar(128) DEFAULT NULL,
  PRIMARY KEY (`id`),
  KEY `city` (`city`)
) ENGINE=InnoDB;

那麼sql語句可以這樣寫

select city,name,age from t where city='杭州' order by name limit 1000  ;

接下來我們看下explain的結果

圖中的Extra這一列下面的Using filesort表示需要排序,MySQL會為每個連線分配一塊記憶體用於排序,就是sort_buffer,sort_buffer_size可以調整該排序記憶體大小

因為我們where條件用到了city,所以我們在city上面建立了索引

我們先看下該索引結構

從圖中可以看出滿足city=杭州的條件是ID_X到ID_Y之間的資料

通常情況下這個語句的執行流程如下:

1.初始化sort_buffer,確定放入name,age,city三個欄位

2.從索引city中找到第一個符合條件的資料,也就是ID_X這個

3.取出索引中id的值,回表查詢name,age,city的資料放入sort_buffer中

4.從索引city取下一個符合條件的id

5.重複步驟3,4直到city的值不滿足city=杭州的條件,也就是圖中ID_Y

6.對sort_buffer中的資料按照name排序

7.按照排序結果取前1000行資料返回給客戶端

我們把這個排序過程叫全欄位排序

如下圖所示

上圖按name排序這個動作可能在記憶體中完成也可能需要外部排序,這取決於排序需要的記憶體大小和sort_buffer_size這個引數

如果排序需要的記憶體大於sort_buffer_size設定的數值,那麼就需要使用磁碟臨時檔案輔助排序

 

rowid排序

在上面的那個全欄位排序中,只對原表查詢了一次,但是如果查詢的欄位很多的話,那麼sort_buffer中就會很多資料,就會使用到

磁碟臨時輔助檔案排序,這樣效能會變差。

那麼如果mysql認為單行資料過大會怎麼辦呢?

接下來設定一下這個引數為16

max_length_for_sort_data這個引數是mysql專門用來控制用於排序的行資料的單行的長度的一個引數,如果單行資料的欄位的長度超過這個引數設定的值

那麼就會使用rowid排序,比如說我們這個例子中name,age,city這三個欄位的單行資料長度之和要是大於16,那麼就會使用rowid排序

排序流程:

1.初始化sort_buffer,確定放入id,name

2.取出city索引中第一個滿足條件的索引的id值

3.到主鍵id索引裡面取出整行,取出name,id欄位放入sort_buffer

4.去下一個符合條件的索引記錄,放入sort_buffer中

5.重複步驟3.4直到不滿足city=杭州

6.對sort_buffer中的資料按照name進行排序

7.遍歷排序結果取出前1000行的資料的id,去表中查詢出name,age,city返回給客戶端

可以看出來rowid排序比全欄位排序多了一次表查詢就是步驟7

 

相關文章