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 MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...