一、前言
這篇文章動筆之前,光標題就思考了半天,因爲文章的起源是一位網友的評論,問的問題比較犀利且分散,實在是不容易擬定標題。博主就藉着這個機會研究下這些問題,分別作答一下。
這裏是網友的提問:
文章鏈接: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數據
這個16kb
是innodb
默認的頁大小,爲什麼會有這個概念呢,因爲當涉及到數據庫讀寫的時候,規定數據庫每次讀寫都是以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