【MySQL篇】DEPENDENT SUBQUERY(依賴性子查詢)優化:從百秒到秒級響應的四種優化辦法

💫《博主介紹》:?又是一天沒白過,我是奈斯,從事IT領域?

💫《擅長領域》:??擅長阿里云AnalyticDB for MySQL(分布式數據倉庫)、Oracle、MySQL、Linux、prometheus監控;并對SQLserver、NoSQL(MongoDB)有了解??

💖💖💖大佬們都喜歡靜靜的看文章,并且也會默默的點贊收藏加關注💖💖💖

? ? 數據庫中的慢查詢,真的是讓人抓狂!對于慢查詢不僅會讓數據庫服務器的資源使用率瞬間飆升,甚至一個慢查詢就能把?CPU內存IO?等資源幾乎全部占滿?,并且還會導致后續的查詢全部變慢,從而導致系統響應速度直接癱了📉,所以優化慢SQL是一件非常非常重要的事情。

? ? 優化慢 SQL 不僅需要對 SQL 語法了如指掌 🧠,還得熟悉MySQL中各種執行計劃中的訪問路徑,比如全表掃描、索引掃描、臨時表等。最近博主正好遇到一個經典的慢 SQL 問題,就是標題提到的?DEPENDENT SUBQUERY(依賴子查詢) 。這個案例非常典型,優化過程也很有意思,所以整理出來分享給大家。

? ? ? ? ? ??

目錄

生產 DEPENDENT SUBQUERY 案例分享:

優化DEPENDENT SUBQUERY方法一:改寫成CTE(Common Table Expression,公用表表達式)(需要注意:CTE是MySQL 8.0.1版本中引入的,所以8.0以下的版本沒有辦法改寫成CTE寫法)

優化DEPENDENT SUBQUERY方法二:將 IN 子查詢重寫為?JOIN

優化DEPENDENT SUBQUERY方式三:使用 EXISTS 替代 IN 子查詢

優化DEPENDENT SUBQUERY方法四:創建索引。無論使用上述哪種方法,確保相關列上有索引可以顯著提升性能。


? ? ? ? ? ? ? ? ? ?

? ? 在開始之前先聊一聊 DEPENDENT SUBQUERY(依賴性子查詢)?。在MySQL8.0官網文檔中描述DEPENDENT SUBQUERY是執行計劃中的select_type列的輸出。

? ? 在MySQL中,?DEPENDENT SUBQUERY 是一種子查詢類型,它的執行依賴于外部查詢的每一行數據。這意味著,對于外部查詢的每一行,子查詢都會重新執行一次。這種類型的子查詢通常會導致性能問題,尤其是在數據量較大的情況下。

? ? ? ? ? ?

DEPENDENT SUBQUERY 的工作原理

  • 依賴關系:?DEPENDENT SUBQUERY 的子查詢會引用外部查詢中的列,因此它的執行結果依賴于外部查詢的當前行。
  • 執行次數:對于外部查詢的每一行,子查詢都會重新執行一次。如果外部查詢有?N 行,子查詢就會執行?N 次。
  • 性能影響:由于子查詢需要重復執行,這種類型的子查詢通常會導致性能問題,尤其是在外部查詢返回大量數據時。

? ? 以下是一個簡單的圖示,幫助理解?DEPENDENT SUBQUERY的執行流程:

? ?

DEPENDENT SUBQUERY 案例:

SELECT *
FROM employees e
WHERE EXISTS (SELECT 1FROM departments dWHERE d.manager_id = e.employee_id
);

? ? ? ? ? ? ? ?

在這個查詢中:

  • 外部查詢從?employees 表中檢索數據。
  • 子查詢檢查 departments 表中是否存在?manager_id?等于當前?employee_id 的記錄。
  • 對于 employees 表中的每一行,子查詢都會執行一次。

? ? 如果執行計劃中顯示子查詢的?select_type ?DEPENDENT SUBQUERY ,這意味著子查詢會為?employees 表中的每一行執行一次.這種案例很容易理解,因為在子查詢中引用了外部查詢中的表,所以子查詢會為外部表中的每一行執行一次。

? ? ? ? ? ?


? ? ? ?

關于上述SQL DEPENDENT SUBQUERY 的執行流程:

  • 步驟一:外部查詢開始執行。從?employees 表中讀取第一行數據。
  • 步驟二:子查詢執行。根據當前行的?employee_id?,在 departments 表中查找是否存在匹配的?manager_id?
  • 步驟三:返回結果。如果子查詢返回結果,則外部查詢的當前行被保留;否則,丟棄。
  • 步驟四:重復執行。外部查詢繼續讀取下一行,重復上述步驟,直到所有行都被處理。

? ? ? ? ? ? ? ? ? ? ? ? ?

生產 DEPENDENT SUBQUERY 案例分享:

? ? SQL中部分表名和字段有點敏感,所以博主用通用方式表達。這個SQL不長,并且邏輯也不復雜,硬是執行了 幾百秒 都沒有返回結果😰。liu_mysqloltp_ywcs_org表只有9萬行數據,liu_mysqloltp_ywcs_cmn更是只有4092行數據。

SELECTa.Region_Name,t.* 
FROMliu_mysqloltp_ywcs_org t,liu_mysqloltp_ywcs_cmn a 
WHEREt.REGION_ID = a.id AND t.Hospital_Name IN ( SELECT tt.Hospital_Name FROM liu_mysqloltp_ywcs_org tt GROUP BY tt.Hospital_Name HAVING count(*) > 1 );

? ? ??

? ? 通過explain查看一下這個SQL的執行計劃,在這個查詢中:

  • 外部查詢:從?liu_mysqloltp_ywcs_org?表和?liu_mysqloltp_ywcs_cmn?表中選擇數據。
  • 子查詢:查找?liu_mysqloltp_ywcs_org?表中?Hospital_Name?出現次數大于 1 的記錄。
  • 問題:子查詢是?DEPENDENT SUBQUERY?,會為外部查詢的每一行執行一次,導致性能低下。

? ? 主要性能瓶頸是?DEPENDENT SUBQUERY?和全表掃描,可以看出有以下兩個優化點:

  • PRIMARY?表?a?的掃描:從?ALL?變為?ref??range,減少掃描行數。

  • DEPENDENT SUBQUERY:被消除或優化為?JOIN ,減少子查詢的執行次數。

? ? ? ? ? ? ? ? ? ??

優化DEPENDENT SUBQUERY方法一:改寫成CTE(Common Table Expression,公用表表達式)(需要注意:CTE是MySQL 8.0.1版本中引入的,所以8.0以下的版本沒有辦法改寫成CTE寫法)

? ? with as 是 SQL 中用于定義?CTE(Common Table Expression,公用表表達式) 的語法。它允許你在一個查詢中定義一個臨時的命名結果集,這個結果集可以在同一個查詢中多次引用。WITH AS 的主要作用是提高查詢的可讀性和可維護性,尤其是在處理復雜查詢時。

? ? ??

作用:把重復用到的sql語句放在with as里面,取一個別名,后面的查詢就可以用它。對大批量的sql語句起到一個優化的作用,而且清楚明了

優點:可讀性增強,比如對特定with子查詢取個有意義的名字。With子查詢只執行一次,將結果存儲在用戶臨時表空間中,多次引用,增強性能

? ? ? ?

WITH DuplicateHospitals AS (SELECTtt.Hospital_NameFROMliu_mysqloltp_ywcs_org ttGROUP BYtt.Hospital_NameHAVINGCOUNT(*) > 1
)
SELECTa.Region_Name,t.*
FROMliu_mysqloltp_ywcs_org t
JOINliu_mysqloltp_ywcs_cmn a ON t.REGION_ID = a.id
JOIN
DuplicateHospitals dh ON t.Hospital_Name = dh.Hospital_Name;

優化點如下:

  • DuplicateHospitals 是一個 CTE,用于查找 liu_mysqloltp_ywcs_org 表中 Hospital_Name 出現次數大于 1 的記錄。
  • 這個 CTE 只執行一次,結果會被緩存供后續查詢使用。避免了原始查詢中 IN? 子查詢的重復執行。
  • 主查詢從 liu_mysqloltp_ywcs_org 表和 liu_mysqloltp_ywcs_cmn 表中選擇數據。
  • 通過 JOIN DuplicateHospitals ?CTE 與 liu_mysqloltp_ywcs_org 表關聯,過濾出 Hospital_Name 出現次數大于 1 的記錄。

? ? ? ? ? ? ? ??

優化DEPENDENT SUBQUERY方法二:將 IN 子查詢重寫為?JOIN

? ? 可以將?IN?子查詢重寫為?JOIN?,避免?DEPENDENT SUBQUERY??IN?子查詢可能會導致性能問題,尤其是在子查詢返回的結果集較大時。可以嘗試將子查詢改寫為?JOIN?,這樣可以減少查詢的復雜度。

SELECTa.Region_Name,t.*
FROMliu_mysqloltp_ywcs_org t
JOIN liu_mysqloltp_ywcs_cmn a ON t.REGION_ID = a.id
JOIN (SELECT tt.Hospital_NameFROM liu_mysqloltp_ywcs_org ttGROUP BY tt.Hospital_NameHAVING COUNT(*) > 1
) sub ON t.Hospital_Name = sub.Hospital_Name;

優化點如下:

  • 子查詢被提取為一個派生表(sub),只執行一次。
  • 外部查詢通過 JOIN 與派生表關聯,避免了 DEPENDENT SUBQUERY

? ? ? ? ? ? ? ? ? ??

優化DEPENDENT SUBQUERY方式三:使用 EXISTS 替代 IN 子查詢

? ? EXISTS?通常比?IN?更高效,因為它可以在找到第一個匹配項后立即停止搜索。

SELECTa.Region_Name,t.* 
FROMliu_mysqloltp_ywcs_org t
JOINliu_mysqloltp_ywcs_cmn a 
ONt.REGION_ID = a.id 
WHEREEXISTS (SELECT 1 FROM liu_mysqloltp_ywcs_org tt WHERE tt.Hospital_Name = t.Hospital_Name GROUP BY tt.Hospital_Name HAVING COUNT(*) > 1); 

優化點如下:

  • EXISTS 子查詢在找到第一個匹配項后就會停止搜索,避免了不必要的掃描。
  • 對于依賴子查詢,EXISTS 通常比 IN 更高效,因為它不需要緩存結果集。
  • EXISTS 可以更好地利用索引,尤其是在子查詢中使用了索引列時。

? ? ? ? ? ? ? ? ? ? ? ??

優化DEPENDENT SUBQUERY方法四:創建索引。無論使用上述哪種方法,確保相關列上有索引可以顯著提升性能。

  • 在 liu_mysqloltp_ywcs_org 表的 REGION_ID 列上創建索引:

CREATE INDEX idx_region_id ON liu_mysqloltp_ywcs_org(REGION_ID);
  • 在 liu_mysqloltp_ywcs_org 表的 Hospital_Name 列上創建索引:

??

CREATE INDEX idx_Hospital_Name ON liu_mysqloltp_ywcs_org(Hospital_Name);
  • 在 liu_mysqloltp_ywcs_cmn 表的 id 列上創建索引:
CREATE INDEX idx_id ON liu_mysqloltp_ywcs_cmn(id);

? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?

? ? 關于?DEPENDENT SUBQUERY?的優化分享就到這里。?博主覺得這個案例真的是非常經典,堪稱慢 SQL 優化的“教科書級”范例 📚。通過這次優化,不僅解決了性能瓶頸,還加深了對 MySQL 執行計劃的理解。

? ? 以后,博主還會繼續分享更多有趣的慢 SQL 優化案例 ,比如索引失效、全表掃描、臨時表濫用等。如果你也遇到過類似的“坑”,歡迎在評論區留言討論 💬,一起交流學習,共同進步!

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

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

相關文章

全文 - MLIR Toy Tutorial Chapter 1: Toy Language and AST

Toy 語言 本教程,將會借助一個玩具語言來講解,這個語言我們稱其為 Toy。Toy 是一個基于張量的語言,它允許你定義函數,執行一些數學計算,并且打印結果。做這樣的設定,是因為我們希望讓教程保持簡明&#xff…

排序復習_代碼純享

頭文件 #pragma once #include<iostream> #include<vector> #include<utility> using std::vector; using std::cout; using std::cin; using std::endl; using std::swap;//插入排序 //1、直接插入排序&#xff08;穩定&#xff09; void InsertSort(vecto…

CSS語言的雙向鏈表

CSS語言的雙向鏈表 引言 在計算機科學中&#xff0c;數據結構是一個極為重要的概念&#xff0c;而鏈表則是最常見的數據結構之一。鏈表可以分為單向鏈表和雙向鏈表&#xff0c;其中雙向鏈表因其靈活性和高效性而受到廣泛應用。在前端開發的領域&#xff0c;尤其是CSS&#xf…

簡單理解機器學習中top_k、top_p、temperature三個參數的作用

AI系列文章&#xff1a; AWS AI認證考試中經常提及幾個重要的工具介紹 簡單理解機器學習中top_k、top_p、temperature三個參數的作用 用Deepseek Kimi 快速生成高質量的ppt 在機器學習中&#xff0c;top_k、top_p 和 temperature 是用于控制生成模型&#xff08;如語言模型…

紅寶書第十三講:詳解JavaScript核心對象:Array、Object、Date、RegExp

紅寶書第十三講&#xff1a;詳解JavaScript核心對象&#xff1a;Array、Object、Date、RegExp 資料取自《JavaScript高級程序設計&#xff08;第5版&#xff09;》。 查看總目錄&#xff1a;紅寶書學習大綱 一、Object&#xff1a;萬物皆對象的“盒子” Object是JavaScript中…

昆侖技術重構AI大模型落地范式,長期作“加法”迎來國產生態化“拐點”

作者 | 曾響鈴 文 | 響鈴說 DeepSeek的爆火&#xff0c;在業內迅速掀起了一場國產化的變革。“國產大模型國產算力”軟硬協同的范式正在被重構&#xff0c;AI產業國產化的含金量持續提升&#xff0c;越來越多的企業在這一趨勢下加速走上數智化轉型路徑。 其中&#xff0c;以…

原開源鴻蒙倉庫停止更新

2月24日&#xff0c;gitee 上的開源鴻蒙組織&#xff0c;所有代碼停止更新&#xff0c;查看代碼倉顯示已關閉&#xff0c;不少小伙伴以為停止更新了&#xff0c;發生了什么&#xff1f; 原因很簡單&#xff0c;所有代碼倉遷移至 Gitcode&#xff0c;至于為什么改用 Gitcode&…

Spring Boot框架中常用注解

以下是Spring Boot框架中常用注解的詳細說明&#xff0c;包括名稱、用途、用法、使用位置及擴展示例&#xff0c;按功能模塊分類整理&#xff1a; 一、核心啟動與配置注解 1. SpringBootApplication 用途&#xff1a;主啟動類注解&#xff0c;整合了 Configuration、EnableAu…

Azure Delta Lake、Databricks和Event Hubs實現實時欺詐檢測

設計Azure云架構方案實現Azure Delta Lake和Azure Databricks&#xff0c;結合 Azure Event Hubs/Kafka 攝入實時數據&#xff0c;通過 Delta Lake 實現 Exactly-Once 語義&#xff0c;實時欺詐檢測&#xff08;流數據寫入 Delta Lake&#xff0c;批處理模型實時更新&#xff0…

車載以太網網絡測試 -23【TCPUDP通信示例】

1 摘要 在車載通信場景中&#xff0c;TCP以及UDP的通信可以用于多種應用&#xff0c;例如車輛狀態監控、遠程控制、數據采集等。以下是詳細的代碼示例&#xff0c;展示了如何使用Python實現簡單的TCP客戶端與服務端通信以及簡單的UDP客戶端與服務端通信&#xff0c;并模擬了車…

SpringBoot大學生競賽管理系統設計與實現

一個用于管理大學生競賽報名、信息查詢與競賽管理的系統&#xff0c;采用了現代化的SpringBoot框架進行開發。該系統的主要功能包括學生信息管理、教師信息管理、競賽報名審核、競賽信息管理等模塊&#xff0c;適用于學校或教育機構進行競賽活動的組織與管理。系統界面簡潔&…

深入解析libsunrpc:構建分布式系統的核心RPC庫

深入解析libsunrpc&#xff1a;構建分布式系統的核心RPC庫 引言 在分布式系統開發中&#xff0c;遠程過程調用&#xff08;Remote Procedure Call, RPC&#xff09; 是連接不同節點、實現跨網絡服務調用的關鍵技術。作為SUN公司開源的經典RPC實現&#xff0c;libsunrpc 憑借其…

MinIO搭建部署

1、命令行安裝 訪問monio官網下載應用程序 # wget https://dl.min.io/server/minio/release/linux-amd64/archive/minio-20250228095516.0.0-1.x86_64.rpm -O minio.rpm # sudo dnf install minio.rpm # mkdir ~/minio # minio server ~/minio --console-address :90012、dock…

Linux修改SSH端口號

我這里那RedHat系列的操作系統舉例,修改SSH端口號 修改SSH配置文件:/etc/ssh/sshd_config,將端口號修改為2222.vim /etc/ssh/sshd_config重啟SSH服務systemctl restart sshd# 如果是比較舊的OS,使用下面的命令重啟 service ssh restart驗證端口更改是否成功netstat -tulnp …

【嵌入式Linux】基于ArmLinux的智能垃圾分類系統項目

目錄 1. 功能需求2. Python基礎2.1 特點2.2 Python基礎知識2.3 dict嵌套簡單說明 3. C語言調用Python3.1 搭建編譯環境3.2 直接調用python語句3.3 調用無參python函數3.4 調用有參python函數 4. 阿里云垃圾識別方案4.1 接入阿里云4.2 C語言調用阿里云Python接口 5. 香橙派使用攝…

【商城實戰(63)】配送區域與運費設置全解析

【商城實戰】專欄重磅來襲&#xff01;這是一份專為開發者與電商從業者打造的超詳細指南。從項目基礎搭建&#xff0c;運用 uniapp、Element Plus、SpringBoot 搭建商城框架&#xff0c;到用戶、商品、訂單等核心模塊開發&#xff0c;再到性能優化、安全加固、多端適配&#xf…

字節跳動實習生主導開發強化學習算法,助力大語言模型性能突破

目錄 禹棋贏的背景與成就 主要成就 DAPO算法的技術細節 算法優勢 禹棋贏的研究歷程 關鍵時間節點 字節跳動的“Top Seed人才計劃” 計劃特點 小編總結 在大模型時代&#xff0c;經驗不再是唯一的衡量標準&#xff0c;好奇心、執行力和對新技術的敏銳洞察力成為推動技術…

Rust + 時序數據庫 TDengine:打造高性能時序數據處理利器

引言&#xff1a;為什么選擇 TDengine 與 Rust&#xff1f; TDengine 是一款專為物聯網、車聯網、工業互聯網等時序數據場景優化設計的開源時序數據庫&#xff0c;支持高并發寫入、高效查詢及流式計算&#xff0c;通過“一個數據采集點一張表”與“超級表”的概念顯著提升性能…

使用LangChain實現基于LLM和RAG的PDF問答系統

目錄 前言一.大語言模型(LLM)1. 什么是LLM&#xff1f;2. LLM 的能力與特點 二、增強檢索生成(RAG)三. 什么是 LangChain&#xff1f;1. LangChain 的核心功能2. LangChain 的優勢3. LangChain 的應用場景4. 總結 四.使用 LangChain 實現基于 PDF 的問答系統 前言 本文將介紹 …

群核科技持續虧損近18億:營銷費用偏高,市場份額優勢面臨挑戰

《港灣商業觀察》施子夫 2025年開年&#xff0c;DeepSeek的爆火讓大眾將目光聚焦到了“杭州六小龍”。其中&#xff0c;杭州群核信息技術有限公司&#xff08;以下簡稱&#xff0c;群核科技&#xff09;因系“六小龍”中首家啟動上市的公司而被外界更多關注。 在此次遞表港交…