《Mysql - Order By 的工作原理?》


一:概述

  - order by 用於 SQL 語句中的排序。

  - 以  select city,name,age from t where city='杭州' order by name limit 1000 ; 舉例,來了解下排序的工作原理。

  - 為了避免其他因素的影響,我們為 city 字段加上索引

 

二:分析排序

  - 分析

    -  使用 explain 命令來看看這個語句的執行情況。

      - 

  - 可以看到,在 Extra 這個字段中的“Using filesort”表示的就是需要排序。

  - 在排序時候MySQL 會給每個線程分配一塊內存用於排序,稱為 sort_buffer。

 

二:全字段排序(排序字段未使用索引)

  - 什么時候使用全字段排序?

    - 字段較少,數據量較小,排序可在內存中完成,Mysql 的大部分不走索引的排序都是使用 全字段排序完成的。

 

  - 全字段索引排序流程

    - 初始化 sort_buffer,確定放入 name、city、age 這三個字段。

    - 從索引 city 找到第一個滿足 city='杭州’條件的主鍵 id。

    - 到主鍵 id 索引取出整行,取 name、city、age 三個字段的值,存入 sort_buffer 中;

    - 從索引 city 取下一個記錄的主鍵 id;

    - 重復步驟 3、4 直到 city 的值不滿足查詢條件為止。

    - 對 sort_buffer 中的數據按照字段 name 做快速排序;

    - 按照排序結果取前 1000 行返回給客戶端。 

 

  - 流程細節

    - 整個的排序動作,可能在內存中完成,也可能需要使用外部排序,這取決於排序所需的內存和參數 sort_buffer_size。

    - sort_buffer_size,就是 MySQL 為排序開辟的內存(sort_buffer)的大小。

      - 如果要排序的數據量小於 sort_buffer_size,排序就在內存中完成。

      - 但如果排序數據量太大,內存放不下,則不得不利用磁盤臨時文件輔助排序。外部排序一般使用歸並排序算法。

 

三: rowid 排序(排序字段未使用索引)

  - 什么時候使用 rowid 排序?

    - 在 全字段排序 中,只對原表的數據讀了一遍,剩下的操作都是在 sort_buffer 和臨時文件中執行的。

    - 但是存在一個問題,如果查詢要返回的字段很多,sort_buffer 放的字段數太多,這樣內存里能夠同時放下的行數很少,要分成很多個臨時文件,排序的性能會很差。

    - Mysql 認為 全字段排序代價太大,於是使用 rowid 算法排序。

 

  - rowid 排序流程

    - 初始化 sort_buffer,確定放入兩個字段,即 name 和 id。

    - 從索引 city 找到第一個滿足 city='杭州’條件的主鍵 id。

    - 到主鍵 id 索引取出整行,取 name、id 這兩個字段,存入 sort_buffer 中。

    - 從索引 city 取下一個記錄的主鍵 id。

    - 重復步驟 3、4 直到不滿足 city='杭州’條件為止。

    - 對 sort_buffer 中的數據按照字段 name 進行排序。

    - 遍歷排序結果,取前 1000 行,並按照 id 的值回到原表中取出 city、name 和 age 三個字段返回給客戶端。 

 

  - 流程細節

    -  對比 全字段排序流程你會發現,rowid 排序多訪問了一次表 的主鍵索引

 

四: 全字段排序 對比 rowid 排序?

  - 如果 MySQL 實在是擔心排序內存太小,會影響排序效率,才會采用 rowid 排序算法,這樣排序過程中一次可以排序更多行,但是需要再回到原表去取數據

  - 對於 InnoDB 表來說,rowid 排序會要求回表多造成磁盤讀,因此不會被優先選擇。 

 

五:索引排序(排序字段使用索引)

  - 新建立排序字段索引

    - 還是上面的 SQL 查詢, 這里建立 city,name 的聯合索引

 

  - 再看索引排序流程

    - 從索引 (city,name) 找到第一個滿足 city='杭州’條件的主鍵 id。

    - 到主鍵 id 索引取出整行,取 name、city、age 三個字段的值,作為結果集的一部分直接返回;

    - 從索引 (city,name) 取下一個記錄主鍵 id;

    - 重復步驟 2、3,直到查到第 1000 條記錄,或者是不滿足 city='杭州’條件時循環結束。

 

六:排序字段加索引的優點

  - 在排序字段有索引的情況下,查詢過程不需要臨時表,也不需要排序。

  - 同時,也不會掃描全部符合條件的行數,而是找到適合條件既會返回數據。

 

七:其他在排序中中需要注意的。

  - 無條件查詢如果只有order by create_time,即便create_time上有索引,也不會使用到。

    - 因為優化器認為走二級索引再去回表成本比全表掃描排序更高。所以選擇走全表掃描,然后根據老師講的兩種方式選擇一種來排序

 

  - 無條件查詢但是是order by create_time limit m.如果m值較小,是可以走索引的.

    - 因為優化器認為根據索引有序性去回表查數據,然后得到m條數據,就可以終止循環,那么成本比全表掃描小,則選擇走二級索引。

    - 即便沒有二級索引,mysql針對order by limit也做了優化,采用堆排序。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM