Java-96 深入淺出 MySQL 索引與排序機制詳解與優化實踐 Filesort

點一下關注吧!!!非常感謝!!持續更新!!!

🚀 AI篇持續更新中!(長期更新)

AI煉丹日志-31- 千呼萬喚始出來 GPT-5 發布!“快的模型 + 深度思考模型 + 實時路由”,持續打造實用AI工具指南!📐🤖

💻 Java篇正式開啟!(300篇)

目前2025年08月11日更新到:
Java-94 深入淺出 MySQL EXPLAIN詳解:索引分析與查詢優化詳解
MyBatis 已完結,Spring 已完結,Nginx已完結,Tomcat已完結,分布式服務正在更新!深入淺出助你打牢基礎!

📊 大數據板塊已完成多項干貨更新(300篇):

包括 Hadoop、Hive、Kafka、Flink、ClickHouse、Elasticsearch 等二十余項核心組件,覆蓋離線+實時數倉全棧!
大數據-278 Spark MLib - 基礎介紹 機器學習算法 梯度提升樹 GBDT案例 詳解

請添加圖片描述

MySQL 索引與排序機制詳解

兩種排序方式概述

MySQL 查詢處理排序時主要支持兩種方式:filesort 和 index 排序。這兩種方式在性能上有顯著差異,理解它們的區別對于數據庫優化至關重要。

filesort 排序方式

filesort 是 MySQL 的通用排序算法,當無法使用索引排序時就會采用這種方式。其工作流程如下:

  1. 數據獲取階段:首先執行查詢獲取滿足條件的記錄
  2. 排序處理階段:將結果集放入排序緩沖區(sort buffer)
    • 如果數據量小,完全在內存中完成排序
    • 如果數據量大,會使用臨時文件進行多輪歸并排序
  3. 結果返回階段:將排序后的結果返回給客戶端

典型的使用 filesort 的場景包括:

  • 對沒有索引的列進行排序
  • 使用了 ORDER BY 與 GROUP BY 不同的表達式
  • 排序方向與索引定義方向不一致(如索引是 ASC 但查詢要求 DESC)

index 排序方式

index 排序是利用索引本身的有序特性來避免額外的排序操作,其優勢包括:

  1. 直接利用索引:按照索引順序讀取數據,天然有序
  2. 無額外開銷:省去了排序緩沖區的分配和排序計算過程
  3. 性能優勢:特別是對于大型結果集,性能提升顯著

使用 index 排序的條件:

  • ORDER BY 子句中的列必須與索引列順序完全匹配
  • 排序方向(ASC/DESC)必須與索引定義一致
  • 不能跳過索引中的列(遵循最左前綴原則)

性能對比示例

假設有一個包含百萬條記錄的用戶表:

-- 情況1:filesort
SELECT * FROM users WHERE status = 'active' ORDER BY registration_date;-- 情況2:index排序
SELECT * FROM users WHERE status = 'active' ORDER BY id;  -- id是主鍵

在這個例子中,第一種查詢可能需要進行完整的 filesort 操作,而第二種查詢可以直接利用主鍵索引的有序性,性能差異可能達到幾個數量級。

優化建議

  1. 為常用排序條件創建合適的索引
  2. 盡量讓排序條件與索引定義完全匹配
  3. 監控慢查詢日志中的"Using filesort"警告
  4. 適當增大 sort_buffer_size 參數可以減少磁盤臨時文件的使用
  5. 考慮使用覆蓋索引避免回表操作

算法對比

MySQL 文件排序(filesort)算法詳解

雙路排序(Two-pass sorting)

雙路排序是 MySQL 中的傳統排序算法,其工作流程如下:

  1. 第一次磁盤掃描:只讀取排序字段(ORDER BY 子句中指定的列)和行指針(row pointer)
  2. 排序階段:在 sort buffer 中對這些排序鍵進行排序
  3. 第二次磁盤掃描:根據排序后的行指針回表讀取完整的數據行
  4. 結果返回:將排序后的完整數據返回給客戶端

適用場景

  • 當查詢的列很多,或者列數據很大時
  • 當 max_length_for_sort_data 參數值設置較小時
  • 特別是當使用 SELECT * 查詢大量列時

優點:減少了內存使用,因為只需要緩存排序鍵而非整行數據

單路排序(Single-pass sorting)

單路排序是 MySQL 優化的排序算法,其工作流程如下:

  1. 單次磁盤掃描:一次性讀取查詢需要的所有列(包括排序字段和其他字段)
  2. 內存排序:在 sort buffer 中對這些數據進行排序
  3. 結果返回:直接返回已排序的結果集

潛在問題

  • 如果查詢數據超出 sort buffer 大小(由 sort_buffer_size 參數控制)
  • 會導致多次磁盤讀取操作
  • 可能需要創建臨時表
  • 最終產生多次 I/O 操作,反而降低性能

優化建議

  1. 避免使用 SELECT *,只查詢必要的列
  2. 適當增加 sort_buffer_size 參數值
  3. 調整 max_length_for_sort_data 參數值(控制單行數據最大長度)

示例場景

-- 不推薦的寫法(可能導致單路排序性能問題)
SELECT * FROM large_table ORDER BY create_time DESC;-- 推薦的寫法(減少數據傳輸量)
SELECT id, name, create_time FROM large_table ORDER BY create_time DESC;

參數調整示例

-- 增加排序緩沖區大小(默認通常為256KB)
SET sort_buffer_size = 4 * 1024 * 1024;  -- 設置為4MB-- 調整單行排序數據最大長度(默認1024字節)
SET max_length_for_sort_data = 8192;  -- 設置為8KB

EXPLAIN

如果我們使用 EXPLAIN 命令分析 SQL 查詢的執行計劃時:

在結果集的 Extra 列中,如果出現"Using filesort"的提示,這表示 MySQL 在執行查詢時使用了文件排序(filesort)操作。filesort 是一種成本較高的排序方式,當不能使用索引排序時,MySQL 會將結果集放入臨時表并進行排序。這種情況下,我們應該考慮優化查詢或添加適當的索引來提高性能。

優化 filesort 的常見方法包括:

  1. 為 ORDER BY 子句中的列創建合適的索引
  2. 確保 WHERE 條件中的列和 ORDER BY 列使用相同的索引
  3. 減少查詢返回的數據量

相反,如果 Extra 列顯示"Using Index",這表示查詢使用了覆蓋索引(Covering Index),即查詢所需的所有數據都可以從索引中獲取,而不需要回表查詢數據行。這種情況是最理想的:

  1. 查詢性能最優,因為完全避免了訪問數據表
  2. 可以使用 index 排序方式,效率遠高于 filesort
  3. 減少了 I/O 操作,降低了內存使用

在實際開發中,我們應盡量設計查詢使其能夠使用覆蓋索引,具體方法包括:

  1. 創建包含所有查詢字段的復合索引
  2. 避免 SELECT * 查詢,只選擇必要的列
  3. 確保 WHERE、ORDER BY 和 GROUP BY 子句中的列被索引覆蓋

例如,對于查詢:

SELECT id, name FROM users WHERE status = 1 ORDER BY create_time;

創建索引 (status, create_time, id, name) 就能實現覆蓋索引,避免 filesort 操作。

index方式

當我們使用 order by 子句索引組合滿足索引最左前列的時候:

explain select id from wzk_user order by id;

執行結果如下所示:
在這里插入圖片描述
當我們使用 where 子句 + order by子句 索引組合列滿足索引最左前列的時候:

explain select id from user_info where age > 18 order by username;

對應的結果如下所示:

filesort方式

對索引列同時使用了 ASC 和 DESC:

explain select id from user_info order by age asc, username desc;

對應的結果如下所示:
在這里插入圖片描述
where 子句和order by子句滿足最左前綴,但where 子句使用了范圍查詢:

explain select id from user_info where age > 10 order by username;

對應的結果如下所示:
在這里插入圖片描述

order by 或者 where + order by 索引沒有滿足索引最左前列:

explain select id from user_info order by username;

執行結果如下所示:
在這里插入圖片描述
使用了不同的索引,MySQL每次只采用一個索引,order by涉及了兩個索引:

explain select id from user_info order by username, age;

對應的結果如下所示:
在這里插入圖片描述
where 子句與order by子句,使用了不同的索引:

explain select id from user_info order by abs(age);

對應的結果如下所示:
在這里插入圖片描述

ASC DESC

  • ASC:升序(Ascending),從小到大。
  • DESC:降序(Descending),從大到小。
  • SQL 中默認是 ASC,顯式寫 DESC 會反轉結果順序。
SELECT * FROM users ORDER BY age ASC;   -- 年齡小的在前
SELECT * FROM users ORDER BY age DESC;  -- 年齡大的在前

聚簇索引(Clustered Index)與輔助索引(Secondary Index)

  1. 索引結構
  • InnoDB 存儲引擎采用 B+ 樹作為索引結構
  • 聚簇索引:
    • 葉子節點存儲完整的數據記錄(數據即索引)
    • 每個表只能有一個聚簇索引,通常建立在主鍵上
    • 物理存儲順序與索引順序一致
  • 輔助索引(二級索引):
    • 葉子節點只存儲主鍵值,不包含完整數據
    • 通過回表操作獲取完整數據
    • 一個表可以有多個輔助索引
  1. 遍歷方式
  • 升序遍歷:
    • 從 B+ 樹最左葉子節點開始向右順序掃描
    • 示例:SELECT * FROM table ORDER BY id ASC
  • 降序遍歷:
    • 從 B+ 樹最右葉子節點開始向左順序掃描
    • 示例:SELECT * FROM table ORDER BY id DESC
  1. 性能特點
  • 聚簇索引優勢:
    • 范圍查詢效率高(數據物理連續)
    • 主鍵查找只需一次IO
  • 輔助索引特點:
    • 需要兩次查找(先查輔助索引,再查聚簇索引)
    • 覆蓋索引可避免回表(查詢字段都在索引中)
  1. 應用場景
  • 聚簇索引:
    • 主鍵查詢
    • 范圍查詢(如 BETWEEN, >, <)
    • 排序操作
  • 輔助索引:
    • 非主鍵字段查詢
    • 多條件查詢(可建立復合索引)
    • 頻繁查詢但更新少的字段聚簇索引(Clustered Index)與輔助索引(Secondary Index)
  1. 索引結構
  • InnoDB 存儲引擎采用 B+ 樹作為索引結構
  • 聚簇索引:
    • 葉子節點存儲完整的數據記錄(數據即索引)
    • 每個表只能有一個聚簇索引,通常建立在主鍵上
    • 物理存儲順序與索引順序一致
  • 輔助索引(二級索引):
    • 葉子節點只存儲主鍵值,不包含完整數據
    • 通過回表操作獲取完整數據
    • 一個表可以有多個輔助索引
  1. 遍歷方式
  • 升序遍歷:
    • 從 B+ 樹最左葉子節點開始向右順序掃描
    • 示例:SELECT * FROM table ORDER BY id ASC
  • 降序遍歷:
    • 從 B+ 樹最右葉子節點開始向左順序掃描
    • 示例:SELECT * FROM table ORDER BY id DESC
  1. 性能特點
  • 聚簇索引優勢:
    • 范圍查詢效率高(數據物理連續)
    • 主鍵查找只需一次IO
  • 輔助索引特點:
    • 需要兩次查找(先查輔助索引,再查聚簇索引)
    • 覆蓋索引可避免回表(查詢字段都在索引中)
  1. 應用場景
  • 聚簇索引:
    • 主鍵查詢
    • 范圍查詢(如 BETWEEN, >, <)
    • 排序操作
  • 輔助索引:
    • 非主鍵字段查詢
    • 多條件查詢(可建立復合索引)
    • 頻繁查詢但更新少的字段

索引與排序的關系

索引排序的基本原理

當 ORDER BY 子句的字段順序與索引順序完全一致且排序方向相同時(都是 ASC 或都是 DESC),MySQL 優化器可以利用索引的有序特性直接返回已排序的結果集,這種優化稱為"索引排序"(Index Order By)。這種情況下,執行計劃中不會出現"Using filesort"的額外操作。

示例:

-- 假設有索引 idx_name_age (name, age)
-- 可以直接使用索引排序的情況
SELECT * FROM users ORDER BY name ASC, age ASC;

無法使用索引排序的情況

  1. 排序方向不一致

    • 當索引字段的排序方向與 ORDER BY 指定的方向不一致時
    • 示例:ORDER BY name ASC, age DESC(索引是 ASC,ASC)
  2. 字段順序不匹配

    • ORDER BY 字段的順序與索引定義的順序不同
    • 示例:ORDER BY age, name(索引是 name, age)
  3. 混合使用 ASC 和 DESC

    • 即使字段順序匹配,但排序方向混合時
    • 示例:ORDER BY name DESC, age ASC
  4. 包含非索引字段

    • ORDER BY 包含不在索引中的字段
    • 示例:ORDER BY name, email(email 不在索引中)

Filesort 操作

當無法使用索引排序時,MySQL 必須執行額外的排序操作(Filesort):

  • 數據會被收集到排序緩沖區
  • 使用快速排序算法在內存中排序
  • 如果數據量太大,會使用臨時文件進行外部排序
  • 在 EXPLAIN 結果中會顯示"Using filesort"

最佳實踐建議

  1. 設計匹配查詢的索引

    -- 為常見排序查詢創建專用索引
    CREATE INDEX idx_users_sort ON users(last_name ASC, first_name ASC, hire_date DESC);
    
  2. 使用覆蓋索引

    • 當查詢只需要索引列時,可以完全避免訪問表數據
    • 示例:SELECT user_id FROM users ORDER BY name(user_id 是主鍵)
  3. **避免 SELECT ***:

    • 只查詢需要的列,增加使用覆蓋索引的可能性
  4. 注意多列索引的順序

    • 確保索引列順序與常用 ORDER BY 子句一致
  5. 考慮使用 DESC 索引(MySQL 8.0+):

    CREATE INDEX idx_desc ON table_name (column_name DESC);
    

特殊情況說明

  1. LIMIT 優化

    • 即使需要 Filesort,帶有 LIMIT 的查詢可能只需要排序部分數據
  2. 索引跳躍掃描(MySQL 8.0+):

    • 在某些情況下,即使 ORDER BY 不是索引的最左前綴,也可能使用索引
  3. 分區表排序

    • 在分區表上排序可能會有不同的性能特征# 索引與排序的關系

索引排序的基本原理

當 ORDER BY 子句的字段順序與索引順序完全一致且排序方向相同時(都是 ASC 或都是 DESC),MySQL 優化器可以利用索引的有序特性直接返回已排序的結果集,這種優化稱為"索引排序"(Index Order By)。這種情況下,執行計劃中不會出現"Using filesort"的額外操作。

示例:

-- 假設有索引 idx_name_age (name, age)
-- 可以直接使用索引排序的情況
SELECT * FROM users ORDER BY name ASC, age ASC;

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/918580.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/918580.shtml
英文地址,請注明出處:http://en.pswp.cn/news/918580.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

MLAG雙活網絡妙招:BGP + 靜態VRRP實現智能負載均衡

引言 在現代數據中心和企業網絡架構中&#xff0c;高可用性和負載均衡是核心需求。MLAG&#xff08;Multi-Chassis Link Aggregation&#xff09;技術結合BGP和靜態VRRP的解決方案&#xff0c;為網絡工程師提供了一種高效實現雙活網絡負載均衡的妙招。本文將深入探討這一技術組…

如何構建PHP表單頁面及驗證相關原理(PHP基礎)

文章目錄PHP表單 - 必需字段PHP - 必需字段PHP - 顯示錯誤信息總結PHP表單 - 驗證郵件和URLPHP - 驗證名稱PHP - 驗證郵件驗證URLPHP 完整表單實例 PHP表單 - 必需字段 該章內容將介紹如何設置表單必需字段及錯誤信息 PHP - 必需字段 我們首先給出一個表的驗證規則&#xff0c;…

API如何集成Web搜索功能:原理、實踐與最佳選型

API如何集成Web搜索功能&#xff1a;原理、實踐與最佳選型 在現代智能應用開發中&#xff0c;模型生成結果往往需要融合最新的互聯網信息。通過集成Web搜索工具&#xff0c;模型可以在生成響應前主動檢索網絡&#xff0c;獲取實時數據。這一能力極大提升了智能系統的準確性和時…

Spring Boot項目中調用第三方接口

目錄 步驟1: 添加依賴 步驟2: 配置HTTP客戶端 配置RestTemplate 配置WebClient 步驟3: 在Service層調用接口 使用RestTemplate示例 使用WebClient示例 步驟4: 在Controller層調用Service 注意事項 總結 Spring Boot項目中調用第三方接口 在Spring Boot項目中調用第三…

關系型數據庫:原理、演進與生態全景——從理論基石到云原生的深度巡禮

目錄 一、引言&#xff1a;當“表”成為世界的通用語言 二、理論基石&#xff1a;關系模型與 ACID 三、引擎架構&#xff1a;一條 SQL 的奇幻漂流 四、存儲機制&#xff1a;頁、緩沖池與 WAL 五、并發控制&#xff1a;鎖、MVCC 與隔離級別 六、SQL&#xff1a;聲明式語言…

【軟考架構】計算機網絡中的IP地址表示和子網劃分

在計算機網絡中&#xff0c;IP地址用于唯一標識網絡中的設備。IP地址的表示方式有兩種&#xff1a;IPv4和IPv6。IPv4是當前使用最廣泛的地址格式&#xff0c;而IPv6是為了解決IPv4地址耗盡問題而設計的。 1. IPv4地址 IPv4地址是一個32位的數字&#xff0c;通常用四個十進制數表…

【后端】Spring @Resource和@Autowired的用法和區別

以下是關于 Resource 和 Autowired 兩個依賴注入注解的詳細對比說明&#xff0c;重點關注它們的區別和使用場景&#xff1a;&#x1f4cc; 核心區別總結特性Autowired (Spring)Resource (JSR-250 標準)來源Spring 框架原生注解Java 標準 (javax.annotation)默認注入方式按類型 …

php+apache+nginx 更換域名

phpapachenginx 更換域名? 第 1 步&#xff1a;確認到底是誰在監聽 80/443? 第 2 步&#xff1a;按監聽者修改配置&#x1f539; 場景 A&#xff1a;Apache 直接監聽 80/443&#x1f539; 場景 B&#xff1a;Nginx 監聽 80/443&#xff0c;反向代理到 Apache? 第 3 步&#…

AI 視頻衛士:AI 無人機巡檢,適配多元河道場景的治理利器

河道治理&#xff0c;場景各異&#xff0c;難題不同。城市內河的生活垃圾、景區河道的景觀破壞、工業園區河道的工業廢料&#xff0c;每一種場景都對巡檢工作有著獨特的要求。AI 視頻衛士&#xff0c;憑借強大的 AI 技術&#xff0c;針對不同河道應用場景&#xff0c;打造專屬巡…

累加和校驗原理與FPGA實現

累加和校驗原理與FPGA實現寫在前面一、基礎原理二、舉個例子2.1 進位累加2.2 回卷累加三、FPGA實現3.1 發送端&#xff08;產生校驗和&#xff09;3.2 接收端&#xff08;累加和校驗&#xff09;3.3 仿真結果寫在后面寫在前面 在上文《奇偶校驗原理與FPGA實現》中&#xff0c;講…

深入解析Go設計模式:命令模式實戰

什么是命令模式? 命令模式(Command Pattern)是一種行為型設計模式,它將請求封裝為獨立對象,從而允許客戶端通過不同的請求對象進行參數化配置。該模式支持請求的排隊執行、操作記錄以及撤銷等功能。 命令模式UML類圖如下所示: 命令模式包含五個核心角色,具體說明如下: …

Pytest項目_day11(fixture、conftest)

Fixture fixture是一種類似于setup、teardown&#xff0c;用于測試前后進行預備、清理工作的代碼處理機制 相比于setup、teardown來說&#xff0c;fixture命名更靈活&#xff0c;局限性更少使用conftest.py配置里面可以實現數據共享&#xff0c;不需要import就能自動找到一些配…

DAY 43 復習日

作業&#xff1a; kaggle找到一個圖像數據集&#xff0c;用cnn網絡進行訓練并且用grad-cam做可視化 劃分數據集 import torch import torch.nn as nn import torch.optim as optim from torchvision import datasets, transforms from torch.utils.data import DataLoader impo…

Flink運行時的實現細節

一、Flink集群中各角色運行架構先說Flink集群中的角色吧&#xff0c;有三個分別是客戶端(Client)、JobManager、TaskManager。客戶端負責接收作業任務并進行解析&#xff0c;將解析后的二進制數據發送給JobManager&#xff1b;JobManager是作業調度中心&#xff0c;負責對所有作…

思科、華為、華三如何切換三層端口?

三層交換機融合了二層交換技術與三層轉發技術&#xff0c;具備強大的網絡功能。主流廠商&#xff08;思科、H3C、華為&#xff09;的三層交換機均支持二層端口與三層端口的相互切換&#xff0c;但具體命令存在差異。本文將詳細介紹三大廠商設備的端口切換方法及相關知識。一、各…

springboot的基礎要點

Spring Boot 的核心設計理念是 ??"約定優于配置"??&#xff08;Convention Over Configuration&#xff09;&#xff0c;旨在簡化 Spring 應用的初始搭建和開發過程。以下是需要掌握的核心基礎要點&#xff1a;?一、核心機制??自動配置 (Auto-Configuration)?…

lesson36:MySQL從入門到精通:全面掌握數據庫操作與核心原理

目錄 一、引言&#xff1a;為什么選擇MySQL&#xff1f; 二、MySQL安裝與登錄配置 2.1 環境準備 2.2 登錄指令詳解 三、數據庫核心操作 3.1 數據庫生命周期管理 3.2 數據庫存儲引擎選擇 四、數據表設計與操作 4.1 表結構創建&#xff08;含數據類型詳解&#xff09; …

Spring源碼解析 - SpringApplication run流程-prepareContext源碼分析

prepareContext源碼分析 private void prepareContext(DefaultBootstrapContext bootstrapContext, ConfigurableApplicationContext context,ConfigurableEnvironment environment, SpringApplicationRunListeners listeners,ApplicationArguments applicationArguments, Bann…

HIS系統:醫院信息化建設的核心,采用Angular+Java技術棧,集成MySQL、Redis等技術,實現醫院全業務流程管理。

HIS系統在醫院信息化建設中扮演著核心的角色。它是一個綜合性的信息系統&#xff0c;旨在管理和運營醫院的各種業務&#xff0c;包括門診、住院、財務、物資、科研等。技術細節&#xff1a;前端&#xff1a;AngularNginx后臺&#xff1a;JavaSpring&#xff0c;SpringBoot&…

深度學習-卷積神經網絡-LeNet

卷積神經網絡是一種專門用于處理具有網格結構數據&#xff08;如圖像、音頻等&#xff09;的深度學習模型。它通過卷積層自動提取數據中的特征&#xff0c;利用局部連接和參數共享的特性減少了模型的參數數量&#xff0c;降低了過擬合的風險&#xff0c;同時能夠有效地捕捉數據…