【SQL進階】用EXPLAIN看透SQL執行計劃:從“盲寫“到“精準優化“

用EXPLAIN洞察SQL執行計劃:從"盲目編寫"到"精準優化"

很多開發者在編寫SQL時僅憑直覺,直到查詢超時才發現問題。MySQL內置的EXPLAIN工具能提前揭示查詢執行邏輯,幫助預防性能隱患。本文將帶你掌握EXPLAIN的核心用法,讓SQL優化從經驗導向轉變為數據驅動。

一、EXPLAIN:揭秘SQL查詢的執行過程

EXPLAIN是MySQL強大的查詢分析工具,通過在SQL語句前添加該關鍵字即可獲取詳細的執行計劃,包括:

  • 表的訪問順序
  • 索引使用情況
  • 預估掃描行數
  • 是否存在全表掃描、臨時表或文件排序等性能瓶頸

使用示例

-- 基礎查詢分析
EXPLAIN SELECT id, name FROM products WHERE category='自行車';-- 深度分析復雜查詢
EXPLAIN FORMAT=JSON SELECT * FROM orders JOIN customers ON orders.cust_id=customers.id;

執行結果包含10余個關鍵字段,其中4個核心指標是性能優化的重點依據。

二、四大核心指標:快速定位查詢瓶頸

核心指標優化指南

指標功能說明性能參考值優化重點檢測方法
type表訪問方式最優:const/eq_ref
良好:ref/range
需優化:index/ALL
避免ALL(全表掃描),爭取達到range及以上檢查執行計劃中的type
rows預估掃描行數優秀:<100
良好:100-1000
需優化:≥1000
通過索引優化減少掃描行數對比rows與實際返回行數
key實際使用索引理想:非NULL
需優化:NULL
確保查詢條件、連接和排序字段使用索引驗證key是否為預期索引
Extra附加信息良好:Using index
需優化:filesort/Using temporary
消除文件排序和臨時表關注負面提示信息

1. type:訪問方式(關鍵性能指標)

type反映表的訪問方式,性能從優到劣排序:

類型說明性能優化建議
ALL全表掃描最差必須創建索引
index索引全掃描較差優化查詢范圍
range索引范圍掃描中等合理,可優化范圍
ref非唯一索引匹配良好推薦,保持索引高選擇性
eq_ref唯一索引匹配優秀理想狀態
const常量查詢最優最佳性能

關鍵提示:發現type=ALL(全表掃描)需立即優化。

2. rows:預估掃描行數

rows表示優化器預估的掃描行數,數值與性能成反比:

  • 全表掃描時接近表總行數
  • 高效查詢應遠小于總行數

優化建議

  • rows遠大于實際返回行數時,執行ANALYZE TABLE 表名更新統計信息
  • 通過索引優化將rows控制在1000以內(大數據表需更嚴格)

3. key:實際使用索引

key顯示查詢實際使用的索引,NULL表示未使用索引(通常伴隨type=ALL

常見索引失效原因

  • 索引字段被函數處理(如DATE(create_time)
  • 違反聯合索引最左前綴原則
  • 數據量過小,優化器選擇全表掃描

4. Extra:執行細節

Extra包含關鍵執行信息,需重點關注:

信息說明影響優化建議
Using index覆蓋索引正面無需優化
filesort文件排序負面使用索引排序
Using temporary臨時表負面優化GROUP BY/ORDER BY
Using where回表查詢中性擴展為覆蓋索引

三、實戰案例:用EXPLAIN診斷與優化

案例1:全表掃描優化(type=ALL)

項目優化前優化后
SQLSELECT * FROM products WHERE category='自行車'同左,添加idx_category索引
typeALLref
keyNULLidx_category
rows1000005000
ExtraUsing whereUsing index(若只查索引字段)
執行時間1.2s0.06s

優化步驟

  1. 創建索引:CREATE INDEX idx_category ON products(category);
  2. 原理:通過索引快速定位category='自行車'的記錄,避免全表掃描。

案例2:filesort優化(Extra=filesort)

項目優化前優化后
SQLSELECT * FROM orders WHERE user_id=100 ORDER BY create_time同左,添加idx_user_create聯合索引
typerefref
keyidx_user_ididx_user_create
rows5050
ExtrafilesortUsing index
執行時間0.8s0.05s

優化步驟

  1. 創建聯合索引:CREATE INDEX idx_user_create ON orders(user_id, create_time);
  2. 原理:聯合索引包含篩選(user_id)和排序(create_time)字段,利用索引有序性避免filesort。

案例3:索引失效場景匯總

場景A:函數處理索引字段

錯誤示例

EXPLAIN SELECT * FROM orders WHERE DATE(create_time)='2023-01-01';
-- 執行計劃:type=ALL,key=NULL(索引失效)

優化方案

EXPLAIN SELECT * FROM orders 
WHERE create_time BETWEEN '2023-01-01 00:00:00' AND '2023-01-01 23:59:59';
-- 執行計劃:type=range,key=idx_create_time(索引生效)
場景B:使用NOT/!=/<>操作符

錯誤示例

EXPLAIN SELECT * FROM products WHERE price != 100;
-- 執行計劃:type=ALL,key=NULL(索引失效)

優化方案

-- 拆分范圍查詢(適用于數值型字段)
EXPLAIN SELECT * FROM products WHERE price < 100 
UNION ALL 
SELECT * FROM products WHERE price > 100;
-- 執行計劃:type=range,key=idx_price(索引生效)
場景C:OR連接條件(部分字段無索引)

錯誤示例

EXPLAIN SELECT * FROM users WHERE mobile='13800138000' OR email='test@example.com';
-- 執行計劃:type=ALL,key=NULL(僅mobile有索引,email無索引)

優化方案

-- 改為UNION ALL(需兩個字段均有索引)
EXPLAIN SELECT * FROM users WHERE mobile='13800138000'
UNION ALL
SELECT * FROM users WHERE email='test@example.com';
-- 執行計劃:type=ref,key=idx_mobile/idx_email(雙索引生效)
場景D:隱式類型轉換

錯誤示例

EXPLAIN SELECT * FROM users WHERE mobile=13800138000;
-- 執行計劃:type=ALL,key=NULL(mobile為字符串類型,查詢用數字)

優化方案

EXPLAIN SELECT * FROM users WHERE mobile='13800138000';
-- 執行計劃:type=ref,key=idx_mobile(類型匹配,索引生效)

案例4:復合問題優化(全表掃描+filesort)

原始查詢

EXPLAIN SELECT * FROM products 
WHERE price>100 AND category='自行車' 
ORDER BY create_time;
-- 執行計劃:type=ALL,key=NULL,Extra=Using where; filesort(雙問題)

優化步驟

  1. 創建聯合索引:CREATE INDEX idx_cat_price_time ON products(category, price, create_time);
  2. 優化后執行計劃:
    • type=rangekey=idx_cat_price_timeExtra=Using index
    • 掃描行數從50000→800,執行時間從2.1s→0.09s

案例5:大數據量表分頁優化(百萬級數據)

原始查詢

EXPLAIN SELECT * FROM orders 
WHERE user_id=1000 AND status='paid'
ORDER BY create_time DESC 
LIMIT 20 OFFSET 100;
-- 執行計劃:type=ref,key=idx_user_id,Extra=filesort(偏移+排序雙問題)

優化方案

  1. 創建聯合索引:CREATE INDEX idx_user_status_time ON orders(user_id, status, create_time);
  2. 優化后執行計劃:
    • type=refkey=idx_user_status_timeExtra=Using index
    • 執行時間從1.5s→0.07s

四、高效索引創建指南

1. 索引選擇性:判斷索引是否高效

選擇性:字段不重復值數 / 總記錄數(值越接近1,索引越高效)。

行業案例

  • 電商用戶表:
    • user_id:選擇性=1.0(唯一標識,必建索引)
    • gender:選擇性=0.5(僅男/女,不建議建索引)
  • 物流訂單表:
    • order_no:選擇性=1.0(唯一單號,必建索引)
    • status:選擇性=0.2(5種狀態,僅在篩選特定狀態時建索引)

計算示例

-- 低選擇性字段(狀態)
SELECT COUNT(DISTINCT status)/COUNT(*) FROM orders;  -- 結果≈0.2-- 高選擇性字段(訂單號)
SELECT COUNT(DISTINCT order_no)/COUNT(*) FROM orders;  -- 結果≈1.0

注意:索引選擇性計算需要定期更新(ANALYZE TABLE),否則可能因統計信息過期導致誤判。

2. 索引類型與創建規范

單字段索引

為篩選、JOIN、排序字段創建:

-- 篩選字段索引
CREATE INDEX idx_customer_id ON customers(cust_id);-- 長字符串前綴索引(節省空間)
CREATE INDEX idx_product_name ON products(name(20));  -- 取前20字符
聯合索引(最左前綴原則)

聯合索引(a,b,c)僅在查詢包含最左字段時生效:

有效查詢無效查詢
WHERE a=1WHERE b=2(缺最左a)
WHERE a=1 AND b=2WHERE a=1 AND c=3(跳過b)
WHERE a=1 ORDER BY bWHERE b=2 ORDER BY c(缺a)

創建語法

-- 篩選+排序聯合索引(先篩選,后排序)
CREATE INDEX idx_user_status_time ON orders(user_id, status, create_time);

3. 索引數量建議(平衡讀寫性能)

表類型讀/寫比建議索引數量
讀密集表>100:15-10個
均衡表10:1≤5個
寫密集表(如日志、訂單)<10:1≤3個

警示:在超過500萬行的表上創建索引需要評估鎖表時間,建議在業務低峰期執行。

五、查詢性能優化五步法

  1. 編寫基礎查詢:優先確保業務邏輯正確性,獲得準確結果集;
  2. 分析執行計劃:使用EXPLAINEXPLAIN FORMAT=JSON獲取查詢路徑;
  3. 定位性能瓶頸
    • 檢查type字段是否出現ALL/index等低效掃描;
    • 關注rows預估行數是否異常偏高;
    • 排查Extra字段是否包含filesort/temporary等警告;
    • 驗證key字段是否實際使用了目標索引;
  4. 實施優化方案
    • 索引優化:增刪索引、調整聯合索引字段順序;
    • SQL重構:避免索引字段函數計算、用UNION替換OR條件、改進分頁查詢;
  5. 驗證優化效果:對比優化前后執行計劃的typerowsExtra關鍵指標變化。

六、索引使用五大誤區

  1. 索引濫用:盲目增加索引數量,顯著降低數據寫入效率;
  2. 順序錯配:聯合索引中將低區分度字段前置,嚴重削弱索引效果;
  3. 長度不足:過短的前綴索引導致過濾效率低下;
  4. 環境混淆:測試環境機械復制生產索引配置,忽略數據規模差異;
  5. 維護缺失:長期未更新統計信息,造成優化器決策偏差。

核心總結

EXPLAIN作為SQL性能分析的利器,通過typerowskeyExtra四大核心維度精準定位問題。優化本質在于:基于業務特征設計精準索引,嚴格遵守最左前綴原則,規避常見失效場景。切記,最優索引策略是平衡的藝術——在查詢性能和寫入開銷間取得完美平衡。

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

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

相關文章

電影藝術好,電影知識得學

關于電影應該談什么導演風格、演員技術、劇本結構、票房、政治因素等。一、紙上談電影電影制作期&#xff1a;研發、前制、拍攝、后制、發行。一般成員只在某個時期出現。制片和導演會從頭監督到尾。研發期&#xff1a; 劇本概念發想與成形的時期。創作自由度比較大&#xff0c…

FPGA學習筆記——簡易的DDS信號發生器

目錄 一、任務 二、分析 三、ROM IP核配置 四、Visio圖 五、代碼 &#xff08;1&#xff09;.v代碼 &#xff08;2&#xff09;仿真代碼 六、仿真 七、實驗現象 一、任務 用串口模塊&#xff0c;用上位機發送指令&#xff0c;FPGA接收&#xff0c;然后輸出對應的波形&…

在NVIDIA Orin上用TensorRT對YOLO12進行多路加速并行推理時內存泄漏 (中)

接上篇 在NVIDIA Orin上用TensorRT對YOLO12進行多路加速并行推理時內存泄漏&#xff08;上&#xff09; 通過上篇的分析&#xff0c;發現問題在采集數據到傳入GPU之前的階段。但隨著新一輪長時間測試發現&#xff0c;問題依然存在。 如上圖&#xff0c;在運行20多分鐘內存開始…

計數組合學7.17(Murnaghan–Nakayama 規則 )

7.17 Murnaghan–Nakayama 規則 我們已經成功地用基 mλm_\lambdamλ?、hλh_\lambdahλ? 和 eλe_\lambdaeλ? 表示了 Schur 函數 sλs_\lambdasλ?。本節我們將考慮冪和對稱函數 pλp_\lambdapλ?。一個斜分劃 λ/μ\lambda / \muλ/μ 是連通的&#xff0c;如果其分拆圖…

使用 jlink 構建輕巧的自定義JRE

從 JDK 9 開始&#xff0c;Oracle JDK 和 OpenJDK 不再默認包含獨立的 JRE 目錄&#xff0c;而是提供了 jlink 工具&#xff08;Java 鏈接器&#xff09;&#xff0c;允許你根據需求自定義生成最小化的 JRE&#xff08;包含必要的模塊&#xff09;。以下是使用 jlink 生成 JRE …

[IOMMU]面向芯片/SoC驗證工程的IOMMU全景速覽

面向芯片/SoC驗證工程的IOMMU全景速覽 摘要:面向芯片/SoC 驗證工程的 IOMMU 全景速覽:包含基礎概念、主流架構要點(ARM SMMU、Intel VT?d、RISC?V IOMMU),Linux 軟件棧關系,SoC 上的驗證方法(功能、錯誤、性能、系統化流程和覆蓋),以及一個可用的“通用 IOMM…

Jenkins全鏈路教程——Jenkins用戶權限矩陣配置

在企業級CI/CD場景中&#xff0c;“權限混亂”往往比“構建失敗”更致命——測試員誤刪生產流水線、實習生修改關鍵插件配置、多團隊共用賬號導致責任無法追溯……這些問題&#xff0c;99%都能用權限矩陣徹底解決&#xff01;今天&#xff0c;我們不僅會拆解權限矩陣的底層邏輯…

庫函數蜂鳴器的使用(STC8)

使用庫函數控制蜂鳴器&#xff08;STC8&#xff09; 在STC8系列單片機中&#xff0c;可以通過庫函數或直接操作寄存器來控制蜂鳴器。以下是基于STC8庫函數的常用方法&#xff1a; GPIO板蜂鳴器 #include "GPIO.h" #include "Delay.h"void GPIO_config()…

redis8.0.3部署于mac

macOS11因版本過低&#xff0c;安裝redis時&#xff0c;Homebrew和源碼編譯兩種方式都無法成功。將操作系統升級至macOS15再安裝。Redis&#xff08;Remote Dictionary Server&#xff09;是一個開源的內存數據庫&#xff0c;遵守 BSD 協議&#xff0c;它提供了一個高性能的鍵值…

【和春筍一起學C++】(三十三)名稱空間的其他特性

目錄 嵌套式名稱空間 拓展——未命名的名稱空間 嵌套式名稱空間 示例代碼1&#xff1a; namespace electronicEquipment {namespace computer{double price 4999.0;string modelNumber;string name;}namespace ElectronicWatch{double price 99.0;string modelNumber;stri…

異步電動機負載運行特性全解析

異步電動機負載運行特性詳解 ——從空載到負載的完整分析一、為什么需要再談“負載運行” 在上一篇《感應電動機空載特性深度剖析》中&#xff0c;我們已經看到&#xff1a;空載時&#xff0c;若定子加額定電壓&#xff0c;轉子轉速 $n \approx n_s$&#xff08;同步轉速&#…

使用 Ansys Discovery 進行動態設計和分析

Ansys Discovery 是一款多功能工具&#xff0c;為創建模型、探索仿真設計和分析解決方案提供了一個單一的交互式工作區。它允許用戶使用直接建模技術創建和修改幾何結構&#xff0c;定義仿真并與結果實時交互。Discovery 支持結構、流體流動、熱和電磁設計&#xff0c;提供直觀…

力扣熱題100-----118.楊輝三角

案例 給定一個非負整數 numRows&#xff0c;生成「楊輝三角」的前 numRows 行。 在「楊輝三角」中&#xff0c;每個數是它左上方和右上方的數的和。 示例 1: 輸入: numRows 5 輸出: [[1],[1,1],[1,2,1],[1,3,3,1],[1,4,6,4,1]] 示例 2: 輸入: numRows 1 輸出: [[1]] 提示: 1 …

NTP /Chrony 網絡時間協議

一、NTP&#xff08;network time protocol&#xff09;網絡時間協議&#xff1a;實現時間同步&#xff0c;讓設備時間與國際標準時間保持一致設備日志、服務日志需要記錄時間分布式系統&#xff08;分布式數據庫、分布式緩存、分布式儲存、消息隊列&#xff09;時間戳&#xf…

VSCode 刷 LeetCode 算法題配置教程

LeetCode 在線刷題地址&#xff1a;https://leetcode-cn.com/ 一、安裝 Node.js 環境 LeetCode 插件依賴 node.js 運行環境&#xff0c;因此必須先安裝&#xff1a; 前往官網下載安裝&#xff1a;https://nodejs.cn/download/下載好的壓縮包解壓&#xff0c;可以看到當前文件…

非常簡單!從零學習如何免費制作一個lofi視頻

想必大家在網上會看到如下類似的音樂頻道&#xff0c;這類頻道都只是上傳簡單的Lo-Fi音樂帶著循環播放的背景就可以賺錢。 那么上面的效果如何實現的呢&#xff1f;今天做一個可以免費制作lo-Fi音樂的教程。 Lo-Fi音樂&#xff1a; Lo-Fi音樂是一種以低保真度和模擬音色為特點…

基于 RAUC 的 Jetson OTA 升級全攻略

&#x1f4d6; 推薦閱讀&#xff1a;《Yocto項目實戰教程:高效定制嵌入式Linux系統》 &#x1f3a5; 更多學習視頻請關注 B 站&#xff1a;嵌入式Jerry 基于 RAUC 的 Jetson OTA 升級全攻略 0. 引子&#xff1a;常見問題 在 Jetson 平臺做 OTA 升級時&#xff0c;你可能會問&…

MySQL 主備(Master-Slave)復制 的搭建

一、主備架構簡介 Master&#xff08;主庫&#xff09;&#xff1a;負責處理所有寫操作&#xff08;INSERT/UPDATE/DELETE&#xff09;&#xff0c;并記錄二進制日志&#xff08;binlog&#xff09;。Slave&#xff08;備庫&#xff09;&#xff1a;從主庫拉取 binlog&#xff…

【三個數絕對值排序】2022-10-10

緣由絕對值比較&#xff0c;總是跑不過怎么辦-編程語言-CSDN問答 template <class 形參> inline void 算交換(形參& a, 形參& b){ 形參 ab a - b; a - ab; b ab; } template <class 形參> void 三個升序(形參& a, 形參& b, 形參& c) {if (a…

【LoRA模型訓練】Stable Diffusion LoRA 模型秋葉訓練器詳細教程

一、工具簡介與安裝指南 1.1 秋葉 LoRA 訓練器概述 秋葉 LoRA 訓練器&#xff08;基于 Akegarasu/lora-scripts 項目&#xff09;是針對 Stable Diffusion 模型的輕量化微調工具&#xff0c;通過低秩適應&#xff08;LoRA&#xff09;技術實現高效參數微調。其核心優勢在于&a…