mysql的B+樹如何存儲主鍵和數據,磁盤io和innodb頁大小的一些問題

一、前言

      這篇文章動筆之前,光標題就思考了半天,因爲文章的起源是一位網友的評論,問的問題比較犀利且分散,實在是不容易擬定標題。博主就藉着這個機會研究下這些問題,分別作答一下。

這裏是網友的提問:

文章鏈接:mysql的查詢需要遍歷幾次B+樹,理論上需要幾次磁盤I/O?

二、正式作答部分

      這裏分析完這個網友的提問之後,可以大致分爲4個問題來回答,下面博主分別嘗試作答一下,有不正確的地方歡迎大家指正討論~

1、關於B+樹的非葉子節點存儲問題

(1)B+樹的大致結構

在這裏插入圖片描述
      由圖片可以看到,innodb中的B+樹,非葉子節點主要是存儲主鍵的記錄值,按照主鍵的大小順序排成一個單向鏈表。
      葉子節點是存放用戶數據的,頁內數據根據用戶記錄的主鍵大小排列成的單向鏈表。而頁和頁之間是根據主鍵大小順序排成一個雙向鏈表。( PS: 這裏感謝評論區的同學指出錯誤,十分感謝!)

(2)模擬計算下B+樹存儲的數據量

      我們這裏計算下,假設非葉節點不同元素佔用情況爲:下一條記錄指針佔4Byte,id值8Byte,目標記錄指針4Byte,那麼一個4Kb的磁盤塊將大致可以容納250個下級指針。

我們假設,一個4kb的磁盤塊可以容納100條數據(用戶的實際數據):

如果B+樹只有1層,也就是隻有1個用於存放用戶記錄的節點,最多能存放100條記錄。

如果B+樹有2層,最多能存放250×100=2.5W條記錄。

如果B+樹有3層,最多能存放250×250×100=625W條記錄。

(3)網友的問題答案

      原來的計算方式確實是不嚴謹的,只有非葉子節點纔會存有葉子節點的頁記錄,也就是所謂的“下級指針”。實際的存儲方式應該是這篇重寫的部分。

2、磁盤IO次數計算問題

(1)什麼是一次IO

      每次IO其實是磁盤控制器向磁盤發出一次讀/寫指令,給出開始扇區的地址和向後連續讀/寫的扇區的個數。控制器發出的這種指令+數據,就是一次IO,讀或者寫。

(2)IO次數的計算

      首先要明確,我們每次IO都是讀取數據到內存中進行一些計算。當我們遍歷主鍵索引的B+樹查找數據的時候,IO次數是近似於B+樹的層數-1,因爲根節點是一直在內存中的。

      基本上可以理解爲,每次io都是在樹的一層查找符合的id範圍的頁數據,通過對比頁裏面的最大最小主鍵來確定下層的查找範圍。

3、磁盤預讀以及如何保證每次都能拿到innodb的一頁也就是16kb的數據

(1)磁盤預讀

      預讀其實就是利用了局部性原理,具體過程是:對於每個文件的第一個讀請求,系統讀入所請求的頁面並讀入緊隨其後的少數幾個頁面(通常是三個頁面),這時的預讀稱爲同步預讀。

      我們知道對大部分操作系統來說,磁盤的一頁數據是4kb,那麼算上預讀的3頁:

4kb(磁盤一頁的大小) + 12kb(預讀三個頁面) = 16kb

(2)關於每次讀取16kb數據

      這個16kbinnodb默認的頁大小,爲什麼會有這個概念呢,因爲當涉及到數據庫讀寫的時候,規定數據庫每次讀寫都是以16k爲單位的,一次最少從磁盤中讀取16KB的內容到內存中,一次最少把內存中的16KB內容刷新到磁盤中。

(3)磁盤io固定是每次讀取4kb的嗎

      答案明顯不是的,io讀取是可大可小的,具體看指令的內容,並不是每次只能讀取固定的1頁。比如上面解釋一次io概念的時候,我們提到了指令,這個指令是類似於給出兩個參數,第一個參數是要開始讀取的扇區地址,第二個參數是要讀取多少扇區。

      所以每次io的大小是根據指令來決定的,並不是每次只能讀取磁盤的一頁數據,也就是4kb

(4)網友的問題

      主要是明確磁盤中的一頁數據(4kb)和數據庫innodb規定的一頁數據(16kb),這兩個的概念是不一樣的。磁盤io的大小也是根據指令來規定的。對應數據庫讀寫來說,會按照數據庫的配置,每次最少讀寫一頁數據,也就是16kb

4、設置頁大小爲64kb,是否一次io就拿不到對應的數據了,需要多次io?

      其實這個問題上面已經給出了答案。設置innodb頁大小爲64kb之後,我們每次數據庫的讀寫就必須操作64kb的數據了而已,和io次數沒什麼關係的。

      博主看文檔,也沒看到有說到64kb頁大小有什麼缺陷之類的,只知道會增大表空間上限:

InnoDB頁面大小 最大表空間大小:

數據頁大小 最大表空間
4KB 16TB
8KB 32TB
16KB 64TB
32KB 128TB
64KB 256TB

      關於磁盤部分和io部分,博主這裏也就不多做解釋了(博主自己可能也是半斤八兩的),大家可以網上百度百度,瞭解相關的概念。不得不說,這些基礎原理部分還是需要學一學的。

5、參考鏈接

關於IO:https://segmentfault.com/a/1190000021388785
關於索引:https://juejin.im/post/5b4f710be51d45195c073912
掘金小冊,從根兒上理解mysql(各位自行百度,我就不多介紹了)

      歡迎大家指正,討論!另外,今天是全國哀悼日,願我中華蒸蒸日上,災難始終會過去,未來可期!
end

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章