新聞中心
數(shù)據(jù)頁(yè)
我們都知道平時(shí)執(zhí)行crud的時(shí)候,都會(huì)從磁盤(pán)上加載數(shù)據(jù)頁(yè)到Buffer Pool的緩存頁(yè)里去,更新緩存頁(yè)后,由異步線程刷回磁盤(pán)的數(shù)據(jù)頁(yè)。

所以MySQL進(jìn)行數(shù)據(jù)操作的最小單位是數(shù)據(jù)頁(yè),接下來(lái)就分析分析,數(shù)據(jù)頁(yè)到底長(zhǎng)什么樣。
每個(gè)數(shù)據(jù)頁(yè)默認(rèn)16kb的大小,數(shù)據(jù)頁(yè)由多個(gè)部分組成,如下圖所示:
當(dāng)然這么多概念,阿星只會(huì)挑重點(diǎn),循循漸進(jìn)的講,所以大家莫慌。
空閑空間
其實(shí)數(shù)據(jù)頁(yè)還未寫(xiě)入數(shù)據(jù)時(shí),是沒(méi)有數(shù)據(jù)行的,只有空閑空間,一旦寫(xiě)入,空閑空間會(huì)減少一些,直到空閑空間耗盡,具體過(guò)程如下圖:
數(shù)據(jù)頁(yè)滿了,自然需要開(kāi)辟新的數(shù)據(jù)頁(yè)出來(lái)存儲(chǔ)數(shù)據(jù)。
但是隨著數(shù)據(jù)頁(yè)多起來(lái),它們?cè)趺粗郎弦豁?yè)與下一頁(yè)在那呢?
雙向鏈表
其實(shí)在數(shù)據(jù)頁(yè)文件頭中存放了特別多的信息,如當(dāng)前頁(yè)號(hào)、頁(yè)類型、所屬表空間、上一頁(yè)號(hào)、下一頁(yè)號(hào)等等。
所以數(shù)據(jù)頁(yè)是通過(guò)上下頁(yè)號(hào),組成雙向鏈表,如下圖所示:
數(shù)據(jù)頁(yè)內(nèi)部會(huì)存儲(chǔ)一行一行的數(shù)據(jù),每一行數(shù)據(jù)都會(huì)按照主鍵大小進(jìn)行排序存儲(chǔ),同時(shí)每一行數(shù)據(jù)都有指針指向下一行數(shù)據(jù),組成單向鏈表。
但是這個(gè)結(jié)構(gòu)并不高效,假設(shè)根據(jù)主鍵ID查詢數(shù)據(jù),只能進(jìn)入數(shù)據(jù)頁(yè),挨個(gè)挨個(gè)的對(duì)單向鏈表遍歷查詢。
所以要再加點(diǎn)料,把二分查找利用起來(lái)(不知道二分查找是什么,建議百度,這是最基礎(chǔ)算法)
數(shù)據(jù)頁(yè)目錄
這個(gè)料就是數(shù)據(jù)頁(yè)目錄部分,數(shù)據(jù)頁(yè)目錄存儲(chǔ)的內(nèi)容就是主鍵ID和行位置。
這樣就可以通過(guò)數(shù)據(jù)頁(yè)目錄走二分查找,快速定位到數(shù)據(jù)頁(yè)內(nèi)的數(shù)據(jù)行。
如果只有一個(gè)數(shù)據(jù)頁(yè),倒沒(méi)啥問(wèn)題,哪有成千上萬(wàn)個(gè)數(shù)據(jù)頁(yè)呢,還是得一個(gè)一個(gè)進(jìn)數(shù)據(jù)頁(yè),搜索數(shù)據(jù)頁(yè)目錄。
有沒(méi)有覺(jué)得,這似乎是在做全表掃描?
沒(méi)錯(cuò),在沒(méi)有索引的情況下,數(shù)據(jù)庫(kù)就是這樣執(zhí)行的。
索引
如果沒(méi)有索引,查詢速度可以說(shuō)是慢到驚人,一般是不能讓查詢走全表掃描的。
因此數(shù)據(jù)庫(kù)中的查詢,必須要運(yùn)用索引來(lái)加速。
頁(yè)分裂
在說(shuō)索引之前,先說(shuō)個(gè)前置知識(shí),索引的核心基礎(chǔ)要求后一個(gè)數(shù)據(jù)頁(yè)的主鍵值都大于前面一個(gè)數(shù)據(jù)頁(yè)的主鍵值,如果你的主鍵是自增的,可以保證這一點(diǎn)。
但有時(shí)候主鍵并不是自增長(zhǎng)的,可能會(huì)出現(xiàn)后一個(gè)數(shù)據(jù)頁(yè)的主鍵值小于前一個(gè)數(shù)據(jù)頁(yè)的主鍵值。
為了保證索引的核心基礎(chǔ),有個(gè)交換行數(shù)據(jù)的過(guò)程,這個(gè)過(guò)程叫頁(yè)分裂。
過(guò)程如下
- 數(shù)據(jù)頁(yè)0的id=6行數(shù)據(jù)挪到數(shù)據(jù)頁(yè)1
- 數(shù)據(jù)頁(yè)1的頁(yè)目錄更新
- 數(shù)據(jù)頁(yè)1的id=3行數(shù)據(jù)挪到數(shù)據(jù)頁(yè)0
- 數(shù)據(jù)頁(yè)0的頁(yè)目錄更新
主鍵目錄
好了,現(xiàn)在我們以主鍵為例,創(chuàng)建一個(gè)主鍵索引,這個(gè)主鍵索引就是主鍵目錄,它會(huì)維護(hù)所有數(shù)據(jù)頁(yè)的最小主鍵值與對(duì)應(yīng)的頁(yè)號(hào)。
有了主鍵目錄的加持,那找數(shù)據(jù)就非??炝?,過(guò)程如下
- 二分查找主鍵目錄,找到對(duì)應(yīng)的數(shù)據(jù)頁(yè)
- 進(jìn)入數(shù)據(jù)頁(yè),二分查找數(shù)據(jù)頁(yè)目錄,找到對(duì)應(yīng)的行數(shù)據(jù)
可是又來(lái)一個(gè)新問(wèn)題,表里的數(shù)據(jù)可能有幾百萬(wàn),幾千萬(wàn),甚至幾億條數(shù)據(jù),會(huì)有大量的數(shù)據(jù)頁(yè),意味著主鍵目錄要存儲(chǔ)大量的數(shù)據(jù)頁(yè)號(hào)和最小主鍵值。
可能主鍵目錄存儲(chǔ)不下,就算能存儲(chǔ),海量的數(shù)據(jù)僅僅靠二分查找也很吃力。
所以InnoDB實(shí)際上是把主鍵目錄數(shù)據(jù)存儲(chǔ)在多個(gè)數(shù)據(jù)頁(yè)中,我們把這個(gè)數(shù)據(jù)頁(yè)稱為索引頁(yè)
索引頁(yè)
索引頁(yè),顧名思義,就是存儲(chǔ)索引信息的數(shù)據(jù)頁(yè),在數(shù)據(jù)頁(yè)的文件頭部,有頁(yè)類型來(lái)進(jìn)行區(qū)分。
索引頁(yè)會(huì)存儲(chǔ)兩類內(nèi)容,一類是最小主鍵值與索引頁(yè)號(hào),另一類是最小主鍵值與數(shù)據(jù)頁(yè)號(hào)。
把大量的索引信息分散在多個(gè)索引頁(yè)中,再將多個(gè)索引頁(yè)組建成B+樹(shù)結(jié)構(gòu),方便二分查找,結(jié)構(gòu)如下圖:
一直說(shuō)InnoDB的索引是用B+樹(shù)來(lái)組成的,其實(shí)就是這個(gè)意思,當(dāng)然真實(shí)的B+樹(shù)不長(zhǎng)這樣,這樣畫(huà)還是為了幫助大家理解。
現(xiàn)在整個(gè)搜索過(guò)程就十分簡(jiǎn)單了
- 根據(jù)主鍵id二分查找索引頁(yè)
- 找到對(duì)應(yīng)索引頁(yè),再二分查找數(shù)據(jù)頁(yè)
- 進(jìn)入數(shù)據(jù)頁(yè),二分查找數(shù)據(jù)頁(yè)目錄,找到對(duì)應(yīng)的行數(shù)據(jù)
寫(xiě)到這里就結(jié)束了,通過(guò)數(shù)據(jù)頁(yè)到最后的索引,體會(huì)這個(gè)優(yōu)化的過(guò)程,才是本文的重點(diǎn),由于篇幅有限,索引的內(nèi)容后面會(huì)單獨(dú)講解。
網(wǎng)站欄目:InnoDB原理篇:聊聊數(shù)據(jù)頁(yè)變成索引這件事
瀏覽路徑:http://fisionsoft.com.cn/article/dpeojes.html


咨詢
建站咨詢
