用好 explain 媽媽再也不用擔心我的 SQL 慢了

大家好,我是聰,一個樂于分享的小小程序員。在不久之前我寫了一個慢 SQL 分析工具,可以用來分析 Java Mybatis 項目的 SQL 執行情況,其中剛好涉及到了 explain 的使用。感興趣的可以了解一下。

Github 地址?:https://github.com/lhccong/sql-slow-mirror

那么開始我們今天的主題吧,今天的聰碰見了一個當面試官的朋友問我,用過 explain 嗎?說說怎么分析的?

12.jpg

聰:一臉正經的回答道💡

聰:你好面試官,我當然用過 explain,我平時都會那它去查看 SQL 語句是否還能優化。接下來我從主要屬性跟實際例子來講解:

主要的屬性

1) 🌱 id

查詢中每個 SELECT 子句的標識符。簡單查詢的 id 通常為 1,復雜查詢(如包含子查詢或 UNION)的 id 會有多個。

2) 🌱 select_type

描述查詢的類型。比如:簡單查詢顯示為 SIMPLE,子查詢顯示為 SUBQUERY,UNION 中的第二個和后續查詢顯示為 UNION

3)🌱 table

表名稱這個就不用再詳細解釋了吧哈哈。

4) 🌱 partitions

表示查詢涉及到的分區。如果你有使用分區表的話才需要關注此字段。

5) 🌱 type(重點記憶?)

表示訪問的類型,這里也可以看出你的 SQL 的性能。可能的值從最好到最差包括:systemconsteq_refrefrangeindexALL。其中 ALL 表示全表掃描,效率最低。

  • system:

    表示查詢的表只有一行(系統表)。這是一個特殊的情況,不常見。

  • const:

    表示查詢的表最多只有一行匹配結果。這通常發生在查詢條件是主鍵唯一索引,并且是常量比較,以下是一個使用主鍵查找的例子:

    EXPLAIN SELECT * FROM employees WHERE employee_id = 12345;
    
  • eq_ref:

    表示對于每個來自前一張表的行,MySQL 僅訪問一次這個表。這通常發生在連接查詢中使用主鍵或唯一索引的情況下,例子如下:

    EXPLAIN SELECT * FROM employees e JOIN departments d ON e.department_id = d.department_id;
    
  • ref:

    MySQL 使用非唯一索引掃描來查找行。查詢條件使用的索引是非唯一的(如普通索引),例子如下使用了非唯一索引進行查找:

    EXPLAIN SELECT * FROM employees WHERE department_id = 5;
    
  • range:表示 MySQL 會掃描表的一部分,而不是全部行。范圍掃描通常出現在使用索引的范圍查詢中(如 BETWEEN>, <, >=, <=)。下面是范圍查詢:

    EXPLAIN SELECT * FROM employees WHERE salary BETWEEN 50000 AND 100000;
    
  • index:表示 MySQL 掃描索引中的所有行,而不是表中的所有行。即使索引列的值覆蓋查詢,也需要掃描整個索引。以下是使用索引掃描例子:

    EXPLAIN SELECT name FROM employees;
    
  • all(性能最差):表示 MySQL 需要掃描表中的所有行,即全表掃描。這通常出現在沒有索引的查詢條件中。以下是全表掃描例子:

    EXPLAIN SELECT * FROM employees;
    
6) 🌱 possible_keys

表示查詢可能使用的索引列表。

7) 🌱 key

實際使用索引的長度。如果沒有使用索引,該字段顯示為 NULL

8) 🌱 key_len

這個字段表示使用的索引的長度。該值是根據索引的定義和查詢條件計算的。

9) 🌱 rows

MySQL 會估計為了找到所需的行,需要讀取的行數。該值是一個估計值,不是精確值。

10)🌱 filtered

顯示查詢條件過濾掉的行的百分比。一個高百分比表示查詢條件的選擇性好。

11)🌱 Extra

額外信息,如 Using index(表示使用覆蓋索引)、Using where(表示使用 WHERE 條件進行過濾)、Using temporary(表示使用臨時表)、Using filesort(表示需要額外的排序步驟)。

12.jpg

看完這個是不是一目了然了捏,那么接下來跟著我看看實際的分析例子吧!!

實際例子🌰

1.創建 employees 表
CREATE TABLE employees (employee_id INT PRIMARY KEY,first_name VARCHAR(50),last_name VARCHAR(50),department_id INT,salary DECIMAL(10, 2),hire_date DATE,INDEX (department_id)
);

我們要執行以下查詢來查找部門 ID 為 5 且薪水在 50000 到 100000 之間的員工,并按薪水降序排序:

SELECT employee_id, first_name, last_name, salary
FROM employees
WHERE department_id = 5 AND salary BETWEEN 50000 AND 100000
ORDER BY salary DESC;
2.我們先使用 explain 分析計劃進行分析:
EXPLAIN SELECT employee_id, first_name, last_name, salary
FROM employees
WHERE department_id = 5 AND salary BETWEEN 50000 AND 100000
ORDER BY salary DESC;

輸出結果如下:

idselect_typetablepartitionstypepossible_keyskeykey_lenrefrowsfilteredExtra
1SIMPLEemployeesNULLrefdepartment_iddepartment_id4const500020.00Using where; Using filesort
3.分析執行計劃

從執行計劃中看出,typeref,表示使用了 department_id 索引,這是個非唯一索引。keydepartment_id 這個索引,而且 rows 為 5000,表示掃描了 5000 行匹配的 department_id = 5 的條件。從 Extra 看出在應用 WHERE 條件后,還需要進行文件排序來滿足 ORDER BY 子句。

4.找出問題

盡管查詢使用了索引,但由于索引不完全覆蓋查詢的條件和排序,查詢需要進行額外的文件排序。這可能會導致性能瓶頸,特別是在結果集較大時。

5.優化解決它!

創建復合索引

創建一個包含 department_idsalary 的復合索引,這樣可以覆蓋查詢的 WHEREORDER BY 條件:

CREATE INDEX idx_department_salary ON employees (department_id, salary);

復合索引可以使查詢在掃描 department_id 列時,同時按 salary 列排序,避免額外的文件排序。

再次執行計劃分析

優化后的 EXPLAIN 輸出如下:

idselect_typetablepartitionstypepossible_keyskeykey_lenrefrowsfilteredExtra
1SIMPLEemployeesNULLrangeidx_department_salaryidx_department_salary5NULL500100.00Using where
6.分析優化后的結果

從新的 EXPLAIN 輸出中可以看出:

  • type: range,表示使用范圍掃描,這是個相對高效的訪問類型。
  • key: idx_department_salary,表示實際使用了復合索引。
  • rows: 500,估計讀取的行數減少了,因為索引更精確地覆蓋了查詢條件。
  • Extra: 僅顯示 Using where,不再需要文件排序,因為索引已經覆蓋了排序需求。

12.jpg

是不是分析起來很簡單咧,完結撒花!!!!,除了新增聯合索引的方式,你們還知道什么優化策略嗎?

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

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

相關文章

【C#】學習獲取程序執行路徑,Gemini 幫助分析

一、前言&#xff1a; 在Delphi中&#xff0c;如果想要獲取當前執行程序的目錄&#xff0c;程序代碼如下&#xff1a; ExtractFilePath(ParamStr(0)); 今天在分析一個別人做的C#程序時看到了一段C#代碼&#xff0c;意思是獲取執行程序所在的文件目錄&#xff1a; public stat…

基于區塊鏈的Web 3.0關鍵技術研討會順利召開

基于區塊鏈的Web3.0關鍵技術研討會 2024年4月23日&#xff0c;由國家區塊鏈技術創新中心主辦的“基于區塊鏈的web3.0關鍵技術研討會”召開。Web3.0被用來描述一個運行在“區塊鏈”技術之上的“去中心化”的互聯網&#xff0c;該網絡上的主體掌握自己數據所有權和使用權&#xf…

【回眸】git VS repo 區別

git VS repo 區別 1. git&#xff1a;Git是一個開源的分布式版本控制系統&#xff0c;用以有效、高速的處理從很小到非常大的項目版本管理。 2. Repo: Repo是谷歌用Python腳本寫的調用git的一個腳本,Repo實現管理多個git庫。 Git 常用命令 1. git init&#xff1a;在當前目…

【原創】java+springboot+mysql企業郵件管理系統設計與實現

個人主頁&#xff1a;程序猿小小楊 個人簡介&#xff1a;從事開發多年&#xff0c;Java、Php、Python、前端開發均有涉獵 博客內容&#xff1a;Java項目實戰、項目演示、技術分享 文末有作者名片&#xff0c;希望和大家一起共同進步&#xff0c;你只管努力&#xff0c;剩下的交…

Vue的學習 —— <vue組件>

目錄 前言 正文 一、選項式API與組合式API 二、生命周期函數 1、onBeforeMount() 2、onMounted() 3、onBeforeUpdate() 4、onUpdated() 5、onBeforeUnmount() 6、onUnmounted() 三、組件之間的樣式沖突 四、父組件向子組件傳遞數據 1、定義props 2、靜態綁定props…

C++青少年簡明教程:賦值語句

C青少年簡明教程&#xff1a;賦值語句 賦值語句是編程中最基本也是最常用的概念之一&#xff0c;它用于將一個值分配給一個變量。 使用等號&#xff08; 稱為賦值運算符&#xff09;來給變量賦值&#xff0c;賦值語句的左邊是要賦值的變量&#xff0c;右邊是要賦給變量的值。C…

Docker 使用 CentOS 鏡像

使用 docker run 直接運行 CentOS 7 鏡像&#xff0c;并登錄 bash。 C:\Users\yhu>docker run -it centos:centos7 bash Unable to find image centos:centos7 locally centos7: Pulling from library/centos 2d473b07cdd5: Pull complete Digest: sha256:be65f488b7764ad36…

GPT-4o:全面深入了解 OpenAI 的 GPT-4o

GPT-4o&#xff1a;全面深入了解 OpenAI 的 GPT-4o 關于 GPT-4o 的所有信息ChatGPT 增強的用戶體驗改進的多語言和音頻功能GPT-4o 優于 Whisper-v3M3Exam 基準測試中的表現 GPT-4o 的起源追蹤語言模型的演變GPT 譜系&#xff1a;人工智能語言的開拓者多模式飛躍&#xff1a;超越…

連接虛擬機的 redis

用Windows 的 Redis Insight 連接虛擬機的 安裝redis發現連不上 我的redis是新安裝&#xff0c;沒有用戶名密碼&#xff0c;發現是ip問題 127 開頭的被我注釋了&#xff0c;換成了ifconfig查到的ip

vim命令大全(基礎版)

創建一個py文件 vim cs.py一、命令模式 按Esc后&#xff0c;按shift&#xff1a;進入命令模式 :wq # 保存并退出 :q # 退出 :q! # 強制退出 :%d # 刪除全部內容按兩下d&#xff0c;刪除光標所在行 按兩下y&#xff0c;復制光標所在行 按一下p&#xff0c;粘貼復制內容到下…

Android性能:SurfaceFlinger與BufferQueue(3)

Android性能&#xff1a;SurfaceFlinger與BufferQueue&#xff08;3&#xff09; Android顯示系統的組成可以概括為兩大部分&#xff1a;繪制(DrawFrame)合成&#xff08;SurfaceFlinger HWC&#xff09; 繪制&#xff1a;Surface中空的 GraphicBuffer->CPU或者GPU通過Canv…

Python GUI開發- Qt Designer環境搭建

前言 Qt Designer是PyQt5 程序UI界面的實現工具&#xff0c;使用 Qt Designer 可以拖拽、點擊完成GUI界面設計&#xff0c;并且設計完成的 .ui 程序可以轉換成 .py 文件供 python 程序調用 環境準備 使用pip安裝 pip install pyqt5-toolsQt Designer 環境搭建 在pip安裝包…

Vue 常見通信

Vue 常見通信 1、父子通信 父傳子 props&#xff0c;子傳父 events&#xff08;$emit&#xff09;&#xff1b; 通過父鏈 / 子鏈 通信$parent / $children&#xff1b; $refs獲取ref 可以訪問組件實例方法&#xff0c;&#xff1b; 提供與注射provide / inject a t t r s …

使用Processing和PixelFlow庫創建交互式流體太極動畫

使用Processing和PixelFlow庫創建交互式流體太極動畫 引言準備工作效果展示代碼結構代碼解析第一部分&#xff1a;導入庫和設置基本參數第二部分&#xff1a;流體類定義MyFluidDataConfig 類詳解MyFluidData 類詳解my_update 方法詳解流體類定義完整代碼 第三部分&#xff1a;太…

找數字-算法

解法一、數位模擬 比n大的最小數就是n1&#xff0c;當n1時&#xff0c;以下幾種情況會導致n中1的個數發生變化&#xff08;或者不變&#xff09; 1.n的低位連續1的個數count>1&#xff0c;如1011&#xff0c;10111,1111等&#xff0c;加1后使得n中1的個數減少count-1個 解…

基于SVPWM的飛輪控制系統的simulink建模與仿真

目錄 1.課題概述 2.系統仿真結果 3.核心程序與模型 4.系統原理簡介 5.完整工程文件 1.課題概述 基于SVPWM的飛輪控制系統的simulink建模與仿真。SVPWM的核心思想是將逆變器輸出的三相電壓矢量在兩相靜止坐標系&#xff08;αβ坐標系&#xff09;中表示&#xff0c;通過控…

Python3 數據類型詳解:掌握數據基石,編寫高效程序

Python3 中的基本數據類型包括整數&#xff08;int&#xff09;、浮點數&#xff08;float&#xff09;、布爾值&#xff08;bool&#xff09;、字符串&#xff08;str&#xff09;、列表&#xff08;list&#xff09;、元組&#xff08;tuple&#xff09;、集合&#xff08;se…

JAVA static注入 Util使用之Service注入

一般在Util等靜態方法中調用Service或mapper&#xff0c;初始化后會出現空指針異常&#xff1a;java.lang.NullPointerException。 代碼執行優先級的問題&#xff0c;在一個Java類中&#xff0c;存在著靜態代碼塊&#xff0c;靜態方法&#xff0c;構造函數,成員方法等等。不同…

golang中的類和接口

類 在 Go 語言中并沒有類的概念&#xff0c;而是使用結構體來實現面向對象的特性。通過 type 關鍵字可以定義自定義類型&#xff0c;包括結構體類型。下面是一個簡單的示例&#xff1a; package mainimport "fmt"// 定義一個結構體類型 type Person struct {Name s…

只對外公開必要的信息和步驟

隱藏內部結構 使對象的內部結構對外部不可見的內容的處理被稱為封裝化。只公開方法等使用者所需要的最低限度的接口&#xff0c;使用者只能通過外部接口進行訪問。如此一來&#xff0c;使用該類的程序就無須知道其內部的具體實現。 通過封裝化&#xff0c;不僅可以防止調用者…