MySQL / B + 树算法在 mysql 中能存多少行数据?
在面試的時(shí)候,如果問到了 B + 樹這個(gè)東西,或者問到了 MySQL 索引的底層實(shí)現(xiàn),也希望大家能夠進(jìn)一步的發(fā)揮,和面試官探討一下,為什么 B+ 樹一般都是 3 層左右,為什么 3 層的 B + 樹可以存放 2 千萬的數(shù)據(jù),這個(gè)到底是怎么計(jì)算的,計(jì)算的過程大家是要好好消化理解的!
面試的時(shí)候,你能答到這一點(diǎn),絕對(duì)是一個(gè)加分項(xiàng)!
一、InnoDB 一棵 B + 樹可以存放多少行數(shù)據(jù)?
InnoDB 一棵 B + 樹可以存放多少行數(shù)據(jù)?這個(gè)問題的簡(jiǎn)單回答是:約 2 千萬。為什么是這么多呢?因?yàn)檫@是可以算出來的,要搞清楚這個(gè)問題,我們先從 InnoDB 索引數(shù)據(jù)結(jié)構(gòu)、數(shù)據(jù)組織方式說起。
我們都知道計(jì)算機(jī)在存儲(chǔ)數(shù)據(jù)的時(shí)候,有最小存儲(chǔ)單元,這就好比我們今天進(jìn)行現(xiàn)金的流通最小單位是一毛。在計(jì)算機(jī)中磁盤存儲(chǔ)數(shù)據(jù)最小單元是扇區(qū),一個(gè)扇區(qū)的大小是512字節(jié),而文件系統(tǒng)(例如XFS/EXT4)他的最小單元是塊,一個(gè)塊的大小是 4 k,而對(duì)于我們的 InnoDB 存儲(chǔ)引擎也有自己的最小儲(chǔ)存單元——頁(Page),一個(gè)頁的大小是 16 K 。
二、下面幾張圖可以幫你理解最小存儲(chǔ)單元
文件系統(tǒng)中一個(gè)文件大小只有 1 個(gè)字節(jié),但不得不占磁盤上 4 KB的空間。
innodb的所有數(shù)據(jù)文件(后綴為ibd的文件),他的大小始終都是 16384(16k)的整數(shù)倍。
磁盤扇區(qū)、文件系統(tǒng)、InnoDB 存儲(chǔ)引擎都有各自的最小存儲(chǔ)單元。
在 MySQL 中我們的 InnoDB 頁的大小默認(rèn)是 16 k,當(dāng)然也可以通過參數(shù)設(shè)置:
數(shù)據(jù)表中的數(shù)據(jù)都是存儲(chǔ)在頁中的,所以一個(gè)頁中能存儲(chǔ)多少行數(shù)據(jù)呢?假設(shè)一行數(shù)據(jù)的大小是 1 k,那么一個(gè)頁可以存放 16 行這樣的數(shù)據(jù)。
如果數(shù)據(jù)庫只按這樣的方式存儲(chǔ),那么如何查找數(shù)據(jù)就成為一個(gè)問題,因?yàn)槲覀儾恢酪檎业臄?shù)據(jù)存在哪個(gè)頁中,也不可能把所有的頁遍歷一遍,那樣太慢了。所以人們想了一個(gè)辦法,用 B + 樹的方式組織這些數(shù)據(jù)。如圖所示:
我們先將數(shù)據(jù)記錄按主鍵進(jìn)行排序,分別存放在不同的頁中(為了便于理解我們這里一個(gè)頁中只存放 3 條記錄,實(shí)際情況可以存放很多),除了存放數(shù)據(jù)的頁以外,還有存放 鍵值 + 指針 的頁,如圖中 page number = 3 的頁,該頁存放鍵值和指向數(shù)據(jù)頁的指針,這樣的頁由 N 個(gè) 鍵值 + 指針 組成。當(dāng)然它也是排好序的。這樣的數(shù)據(jù)組織形式,我們稱為索引組織表?,F(xiàn)在來看下,要查找一條數(shù)據(jù),怎么查?
如 select * from user where id = 5;
這里 id 是主鍵,我們通過這棵 B + 樹來查找,首先找到根頁,你怎么知道 user 表的根頁在哪呢?其實(shí)每張表的根頁位置在表空間文件中是固定的,即 page number = 3 的頁(這點(diǎn)我們下文還會(huì)進(jìn)一步證明),找到根頁后通過二分查找法,定位到 id = 5 的數(shù)據(jù)應(yīng)該在指針 P5 指向的頁中,那么進(jìn)一步去 page number = 5 的頁中查找,同樣通過二分查詢法即可找到 id = 5 的記錄:
| 5 | zhao2 | 27 |
現(xiàn)在我們清楚了 InnoDB 中主鍵索引 B + 樹是如何組織數(shù)據(jù)、查詢數(shù)據(jù)的,我們總結(jié)一下:
1、InnoDB 存儲(chǔ)引擎的最小存儲(chǔ)單元是頁,頁可以用于存放數(shù)據(jù)也可以用于存放 鍵值 + 指針,在 B + 樹中葉子節(jié)點(diǎn)存放數(shù)據(jù),非葉子節(jié)點(diǎn)存放 鍵值 + 指針。
2、索引組織表通過非葉子節(jié)點(diǎn)的二分查找法以及指針確定數(shù)據(jù)在哪個(gè)頁中,進(jìn)而在去數(shù)據(jù)頁中查找到需要的數(shù)據(jù)。
三、那么回到我們開始的問題,通常一棵B+樹可以存放多少行數(shù)據(jù)?
這里我們先假設(shè) B + 樹高為 2,即存在一個(gè)根節(jié)點(diǎn)和若干個(gè)葉子節(jié)點(diǎn),那么這棵 B + 樹的存放總記錄數(shù)為:根節(jié)點(diǎn)指針數(shù) * 單個(gè)葉子節(jié)點(diǎn)記錄行數(shù)。
上文我們已經(jīng)說明單個(gè)葉子節(jié)點(diǎn)(頁)中的記錄數(shù) = 16K / 1K = 16。(這里假設(shè)一行記錄的數(shù)據(jù)大小為 1 k ,實(shí)際上現(xiàn)在很多互聯(lián)網(wǎng)業(yè)務(wù)數(shù)據(jù)記錄大小通常就是 1 K 左右)。
那么現(xiàn)在我們需要計(jì)算出非葉子節(jié)點(diǎn)能存放多少指針?
其實(shí)這也很好算,我們假設(shè)主鍵 ID 為 bigint 類型,長(zhǎng)度為 8 字節(jié),而指針大小在 InnoDB 源碼中設(shè)置為 6 字節(jié),這樣一共 14 字節(jié),我們一個(gè)頁中能存放多少這樣的單元,其實(shí)就代表有多少指針,即16384? / 14 = 1170。那么可以算出一棵高度為 2 的 B + 樹,能存放 1170*16=18720 條這樣的數(shù)據(jù)記錄。
根據(jù)同樣的原理我們可以算出一個(gè)高度為 3 的 B + 樹可以存放:1170*1170*16 = 21902400 條這樣的記錄。
所以在 InnoDB 中 B + 樹高度一般為 1 - 3 層,它就能滿足千萬級(jí)的數(shù)據(jù)存儲(chǔ)。在查找數(shù)據(jù)時(shí)一次頁的查找代表一次 IO,所以通過主鍵索引查詢通常只需要 1 - 3 次 IO 操作即可查找到數(shù)據(jù)。
五、最后回顧一道面試題
有一道 MySQL 的面試題,為什么 MySQL 的索引要使用 B + 樹而不是其它樹形結(jié)構(gòu)?比如 B 樹?
現(xiàn)在這個(gè)問題的復(fù)雜版本可以參考本文,他的簡(jiǎn)單版本回答是:
因?yàn)?B 樹不管葉子節(jié)點(diǎn)還是非葉子節(jié)點(diǎn),都會(huì)保存數(shù)據(jù),這樣導(dǎo)致在非葉子節(jié)點(diǎn)中能保存的指針數(shù)量變少(有些資料也稱為扇出),指針少的情況下要保存大量數(shù)據(jù),只能增加樹的高度,導(dǎo)致 IO 操作變多,查詢性能變低。
轉(zhuǎn)載于:https://blog.csdn.net/luoyang_java/article/details/92781164
(SAW:Game Over!)
總結(jié)
以上是生活随笔為你收集整理的MySQL / B + 树算法在 mysql 中能存多少行数据?的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Git 索引文件(index file)
- 下一篇: linux cmake编译源码,linu