MySQL Join原理分析(緩衝塊嵌套與索引嵌套迴圈)

来源:https://www.cnblogs.com/phpphp/p/18187458
-Advertisement-
Play Games

場景假設 A表(1000條數據)left join B表(1000條數據)。 嵌套迴圈(Nested-Loop Join) 極簡概括:顧名思義多層迴圈疊加,由於MySQL條數數量有限,所用for迴圈而不用while,在MySQL中就是多層for迴圈。 性能問題:MySQL使用這種作為join方式最簡 ...


場景假設

A表(1000條數據)left join B表(1000條數據)。

嵌套迴圈(Nested-Loop Join)

  • 極簡概括:顧名思義多層迴圈疊加,由於MySQL條數數量有限,所用for迴圈而不用while,在MySQL中就是多層for迴圈。
  • 性能問題:MySQL使用這種作為join方式最簡單,A表joinB表每次join查詢都需要一百萬次內部關聯,每次關聯都需要取一條數據,進行一次IO,若要再關聯C表的1000條,得10億次內部查詢,每個表的數量不過1k,因此需要優化演算法。
  • 附加概念
    • 外層迴圈:從外表中選擇一行。
    • 內層迴圈:對於一行外表的一次迴圈,MySQL會在內表中逐行搜索匹配的行。

緩衝塊

  • 極簡概括:緩衝塊指的是記憶體中的數據塊,當資料庫進行讀取或寫入操作時,通常會將數據載入到緩衝塊中進行處理,以減少對磁碟的訪問頻率,類比開發中的Redis的作用。

緩衝款嵌套迴圈(Block Nested-Loop Join)

  • 極簡概括:取出一批數據放入記憶體中,再對這一批數據進行匹配操作,分批處理(若放不下)+記憶體的性能優勢,能減少io操作。
  • 補充:這塊記憶體有個專業的名詞,叫做join buffer,使用show variables like 'join_buffer%'便可查看大小(預設256KB)。可以隨便找一個或者兩個表試一試,將無索引的列作為join on的關係關聯起來,用explain 查看Extra列,就會顯示Using join buffer (Block Nested Loop)。

索引嵌套迴圈(Index Nested-Loop Join)

  • 前提:所被關聯的列,必須有索引。
  • 原理:利用B+tree的非線性多路查找思路快速定位目標數據,定位到的數據作為主動關聯(A表)或者被關聯(B表)的成員,這意味著不用逐行遍歷,從而提升性能。
  • 舉例:A 關聯 B,假設通過id欄位關聯,原先需要百萬次的內部關聯,受where條件影響(實際開發大概率會用),只查詢出了50條結果。
  • 逐步剖析(包含主觀推理,實際情況有待考證):
    1. 通過下文,知道SQL執行的順序是from->join->on->where->group by->having->select->order by->limit,因此會生成一個百萬級的臨時表(此時還沒有走到過濾或篩選操作的逐行對比流程)。
      但是也不一定,MySQL優化器會根據當前的索引和數據情況,也可能先把A或B表where後內部產生的臨時表(50條),再與另一張表join,從而優化性能,(MySQL優化器為了性能,可以不按照SQL國際標準來運行,這種概率較大)。
    2. 篩選出來50條數據作為臨時表,進行下游環節的處理。
    3. 分析第1步的內部行為:從下文知道1000條數據,MySQL B+tree大概率為2層,也就是50*2 = 100次IO(在樹上查找),然後根據這50條數據join另一張表,由於關聯欄位都是加索引的id欄位,所以另一張表的演算法一致,另一張表也經歷了100次內部IO,所以加起來是200次內部IO,也可以近似的理解為200次內部關聯。

SQL執行順序的邏輯

  1. from用於確定操作對象,放第一位毋庸置疑。
  2. join和on用於關聯,後面的各種處理邏輯依附於關聯後內部創建的臨時表,先生成數據集,才能為後續處理做基礎。
  3. where用於篩選,可以減少後續操作的數據量,提高查詢性能。
  4. group by用於對數據進行分類彙總,不放where前面,是為了避免分組後的數據被where過濾掉(分組分了個寂寞),造成算力浪費和記憶體資源(數據量大還是很消耗算力和記憶體的)的問題。
  5. having用於對分組結果進行過濾,所以要在group by之後。
  6. select用於決定迭代顯示那些列,而不是限制只有這些列才可以參與處理,上游的各種操作(如複雜的where條件)不能受7. select欄位的影響,這也是where後面跟的欄位,不必在select出現的原因。select的本意是處理數據後僅僅返回這些欄位,而不是決定只有這些欄位進行數據處理,所以必定要放偏後的位置。
  7. order by用於結果進行排序,肯定是結果處理後才排序的,理由和group by相似。
  8. limit用於限制返回結果的行數和偏移量,必須是等篩選完分組完拍完序之後再限制,否則可能導致結果有誤。

根據表行數量評估B+tree層數演算法

先排除一些元數據的存儲:數據存儲在頁上,每頁大小16KB,每頁需要開闢一些新的空間來存儲元數據(例如指向上一頁下一頁的指針),頁頭存儲文件頭38位元組,頁面頭56位元組,最小記錄和最大記錄26個位元組,為了保證不出錯,出現了校驗和的機制,這塊功能的存儲被放到了頁尾,占8個位元組。頁里的數據呢,為了方便查找每行的數據,所以包含頁目錄(採用二分法,把查詢複雜度從O(n)優化為O(log n)),這也占空間,這些可以粗略的估計為占用了1KB。

聲明代數:假設非葉子節點指向葉子節點的指針數量為X,葉子節點能夠容納的行數為Y,B+tree層數為Z,那麼能存儲的總行數就是Xz-1 * Y。

計算X:主鍵假設用bigint,占8個位元組,頁號這個元數據占4個位元組,非葉子節點一條數據占12個位元組,15KB / 12B = 1280。
計算Y:假設一個行數據為1KB,也就是說可以放15條數據。

若Z為1:12800 * 15 = 15行
若Z為2:12801 * 15 = 19200行
若Z為3:12802 * 15 = 24576000行
若Z為3:12803 * 15 = 31457280000行

但是這是理想情況,很多主鍵id都用無符號int,能節省4個位元組,行數大小也不確定,所以這是個理論值,究竟是多少,需要根據實際情況討論。

推薦閱讀:

SQL語句執行順序相關問題

MySQL索引底層原理相關問題自總結(難度對標18K-25K薪資,已總結80+,持續更新中)


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 目錄一、文本搜索工具--grep1、簡介2、工作原理3、語法格式4、選項介紹5、實例測試5.1、-i選項5.2、-v選項5.3、-n選項5.4、-c選項5.5、-o選項5.6、-B選項5.7、-A選項5.8、-C選項5.9、-w選項5.10、-E選項5.11、-e選項二、流編輯器--sed1、簡介2 ...
  • 目錄主要使用函數原型:實現過程中幾個易錯細節小結函數:每次讀寫一個字元函數:每次讀寫一行字元函數:每次讀寫一個塊字元 主要使用函數原型: 1.每次讀寫一個字元: int fgetc(FILE *stream); int fputc(int c, FILE *stream); 2.每次讀寫一行字元: ...
  • 問題現象 ps -ef | grep yas 查看無yasom和yasagent進程,且在{資料庫安裝目錄}/om/{資料庫名稱}的目錄下沒有conf、data、log等目錄,確定資料庫不是用yasboot安裝,是用腳本安裝的 問題的風險及影響 非yasboot安裝,ycm無法完成托管,無法監控 問 ...
  • 本文介紹基於Microsoft SQL Server軟體,實現資料庫用戶自定義數據類型的創建、使用與刪除,以及標量值、內嵌表值、多語句表值函數等用戶定義函數的創建、使用、刪除方法~ ...
  • 本文分享自華為雲社區《GaussDB SQL基本語法示例-CASE表達式》,作者:Gauss松鼠會小助手2。 一、前言 SQL是用於訪問和處理資料庫的標準電腦語言。GaussDB支持SQL標準(預設支持SQL2、SQL3和SQL4的主要特性)。 本系列將以《雲資料庫GaussDB—SQL參考》線上 ...
  • 前言 我們先來說說什麼是持久化 持久化顧名思義就是數據長久保存,Redis為什麼需要持久化呢,好呆的問題,Redis數據是存儲在記憶體中的,記憶體數據的特點就是一旦重啟就什麼都沒了 我們將文件由記憶體中保存到硬碟中的這個過程,我們叫做數據保存,也就叫做持久化。但是把它保存下來不是你的目的,最終你還要把它再 ...
  • 作者 | 幸福it民工 來源 | 今日頭條 在資料庫查詢分析中,經常遇到case條件判斷,總結出來供大家參考,下麵通過兩個實例給大家講解。 case用途介紹: CASE是多條件分支語句,相比IF…ELSE語句,CASE語句進行分支流程式控制制可以使代碼更加晰,易於理解。CASE語句也根據表達式邏輯值的真 ...
  • 謹防持久化+未授權訪問漏洞入侵伺服器 CVE編號找不到,CNVD有一個:CNVD-2015-07557(國家信息安全漏洞共用平臺漏洞編號)。 這是我之前寫過的文章,漏洞成因、影響範圍、POC與對抗方案有詳解: 謹防利用Redis未授權訪問漏洞入侵伺服器 RDB(Redis Database、全量保存 ...
一周排行
    -Advertisement-
    Play Games
  • 前言 推薦一款基於.NET 8、WPF、Prism.DryIoc、MVVM設計模式、Blazor以及MySQL資料庫構建的企業級工作流系統的WPF客戶端框架-AIStudio.Wpf.AClient 6.0。 項目介紹 框架採用了 Prism 框架來實現 MVVM 模式,不僅簡化了 MVVM 的典型 ...
  • 先看一下效果吧: 我們直接通過改造一下原版的TreeView來實現上面這個效果 我們先創建一個普通的TreeView 代碼很簡單: <TreeView> <TreeViewItem Header="人事部"/> <TreeViewItem Header="技術部"> <TreeViewItem He ...
  • 1. 生成式 AI 簡介 https://imp.i384100.net/LXYmq3 2. Python 語言 https://imp.i384100.net/5gmXXo 3. 統計和 R https://youtu.be/ANMuuq502rE?si=hw9GT6JVzMhRvBbF 4. 數 ...
  • 本文為大家介紹下.NET解壓/壓縮zip文件。雖然解壓縮不是啥核心技術,但壓縮性能以及進度處理還是需要關註下,針對使用較多的zip開源組件驗證,給大家提供個技術選型參考 之前在《.NET WebSocket高併發通信阻塞問題 - 唐宋元明清2188 - 博客園 (cnblogs.com)》講過,團隊 ...
  • 之前寫過兩篇關於Roslyn源生成器生成源代碼的用例,今天使用Roslyn的代碼修複器CodeFixProvider實現一個cs文件頭部註釋的功能, 代碼修複器會同時涉及到CodeFixProvider和DiagnosticAnalyzer, 實現FileHeaderAnalyzer 首先我們知道修 ...
  • 在軟體行業,經常會聽到一句話“文不如表,表不如圖”說明瞭圖形在軟體應用中的重要性。同樣在WPF開發中,為了程式美觀或者業務需要,經常會用到各種個樣的圖形。今天以一些簡單的小例子,簡述WPF開發中幾何圖形(Geometry)相關內容,僅供學習分享使用,如有不足之處,還請指正。 ...
  • 在 C# 中使用 RabbitMQ 通過簡訊發送重置後的密碼到用戶的手機號上,你可以按照以下步驟進行 1.安裝 RabbitMQ 客戶端庫 首先,確保你已經安裝了 RabbitMQ 客戶端庫。你可以通過 NuGet 包管理器來安裝: dotnet add package RabbitMQ.Clien ...
  • 1.下載 Protocol Buffers 編譯器(protoc) 前往 Protocol Buffers GitHub Releases 頁面。在 "Assets" 下找到適合您系統的壓縮文件,通常為 protoc-{version}-win32.zip 或 protoc-{version}-wi ...
  • 簡介 在現代微服務架構中,服務發現(Service Discovery)是一項關鍵功能。它允許微服務動態地找到彼此,而無需依賴硬編碼的地址。以前如果你搜 .NET Service Discovery,大概率會搜到一大堆 Eureka,Consul 等的文章。現在微軟為我們帶來了一個官方的包:Micr ...
  • ZY樹洞 前言 ZY樹洞是一個基於.NET Core開發的簡單的評論系統,主要用於大家分享自己心中的感悟、經驗、心得、想法等。 好了,不賣關子了,這個項目其實是上班無聊的時候寫的,為什麼要寫這個項目呢?因為我單純的想吐槽一下工作中的不滿而已。 項目介紹 項目很簡單,主要功能就是提供一個簡單的評論系統 ...