MySQL排序「order by」如何實現

定義表:算法

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 ;
複製代碼

sort_buffer_size定義:
MySQL爲排序開闢的內存(sort_buffer)的大小。若是要排序的數據量小於sort_buffer_size,排序就在內存中完成。但若是排序數據量太大,內存放不下,則不得不利用磁盤臨時文件輔助排序sql

經過查看 OPTIMIZER_TRACE,number_of_tmp_files表示排序使用的臨時文件數,外部排序通常使用歸併排序算法。MySQL 將須要排序的數據分紅 12 份,每一份單獨排序後存在這些臨時文件中。而後把這 12個有序文件再合併成一個有序的大文件bash

執行過程:ui

  1. 初始化 sort_buffer,肯定放入 name、city、age 這三個字段;
  2. 從索引 city 找到第一個知足 city='杭州’條件的主鍵 id,也就是圖中的 ID_X;
  3. 到主鍵 id 索引取出整行,取 name、city、age 三個字段的值,存入 sort_buffer 中;
  4. 從索引 city 取下一個記錄的主鍵 id;
  5. 重複步驟 三、4 直到 city 的值不知足查詢條件爲止,對應的主鍵 id 也就是圖中的 ID_Y;
  6. 對 sort_buffer 中的數據按照字段 name 作快速排序;
  7. 按照排序結果取前 1000 行返回給客戶端。

該過程稱爲全字段排序spa

若是查詢返回字段不少的,MySQL會將須要排序的列和主鍵放入sort_buffer,此時執行流程爲:code

  1. 初始化 sort_buffer,肯定放入兩個字段,即 name 和 id;
  2. 從索引 city 找到第一個知足 city='杭州’條件的主鍵 id,也就是圖中的 ID_X;
  3. 到主鍵 id 索引取出整行,取 name、id 這兩個字段,存入 sort_buffer 中;
  4. 從索引 city 取下一個記錄的主鍵 id;
  5. 重複步驟 三、4 直到不知足 city='杭州’條件爲止,也就是圖中的 ID_Y;
  6. 對 sort_buffer 中的數據按照字段 name 進行排序;
  7. 遍歷排序結果,取前 1000 行,並按照 id 的值回到原表中取出 city、name 和 age 三個字段返回給客戶端。

這個過程稱爲rowid排序,相比較全字段排序,它只取了排序字段和主鍵再內存中進行排序,排序結束後還須要遍歷主鍵索引樹,取出須要查詢的值,這個回表的過程比較耗時。cdn

注:blog

若是order by後面的字段走聯合索引,聯合索引中的數據有順序的,好比(city, name, age)三個字段組成聯合索引,會按照city排序,再按照name排序,最後按照age排序,這樣查詢的出的結果集能夠直接返回,不須要使用sort_buffer內存進行排序,能夠使用explain查看extra屬性是否有Using filesort。排序

本文是極客時間丁奇老師《MySQL45講》的讀書筆記,但願你們前去訂閱

相關文章
相關標籤/搜索