More  

小編的世界 優質文選 資料

MySQL 頁完全指南——淺入深出頁的原理


2021年6月22日 - 資料小編 猿牛網 
   

猿牛網

華茜網絡科技(上海)有限公司官方帳號,科技領域愛好者

頁是什麼

首先,我們需要知道,頁(Pages)

是 InnoDB 中管理數據的
最小單元

。Buffer Pool 中存的就是一頁一頁的數據。再比如,當我們要查詢的數據不在 Buffer Pool 中時,InnoDB 會將記錄所在的頁整個加載到 Buffer Pool 中去;同樣的,將 Buffer Pool 中的髒頁刷入磁盤時,也是按照頁為單位刷入磁盤的。

頁的概覽

我們往 MySQL 插入的數據最終都是存在頁中的。在 InnoDB 中的設計中,頁與頁之間是通過一個雙向鏈表
連接起來。

而存儲在頁中的一行一行的數據則是通過單鏈表
連接起來的。

上圖中的 User Records的區域就是用來存儲行數據的。那 InnoDB 為什麼要這麼設計?假設我們沒有頁這個概念,那麼當我們查詢時,成千上萬的數據要如何做到快速的查詢出結果?眾所周知,MySQL 的性能是不錯的,而如果沒有頁,我們剩下的只能是逐條逐條的遍曆數據了。那頁是如何做到快速查詢的呢?在當前頁中,可以通過 User Records 中的連接每條記錄的單鏈表來進行遍曆,如果在當前頁中沒有找到,則可以通過下一頁指針
快速地跳到下一頁進行查詢。

Infimum 和 Supremum

有人可能會說了,你在 User Records中還不是通過遍曆來解決的,你就是簡單地把數據分了個組而已。如果我的數據根本不在當前這個頁中,那我難道還是得把之前的頁中的每一條數據全部遍曆完?這效率也太低了當然,MySQL 也考慮到了這個問題,所以實際上在頁中還存在一塊區域叫做 The Infimum and Supremum Records,代表了當前頁中最大
最小
的記錄。

有了 Infimum Record和 Supremum Record ,現在查詢不需要將某一頁的 User Records全部遍曆完,只需要將這兩個記錄和待查詢的目標記錄進行比較。比如我要查詢的數據 id = 101,那很明顯不在當前頁。接下來就可以通過下一頁指針
跳到下頁進行檢索。

使用Page Directory

可能有人又會說了,你這 User Records裏不也全是單鏈表嗎?即使我知道我要找的數據在當前頁,那最壞的情況下,不還是得挨個挨個的遍曆100次才能找到我要找的數據?你管這也叫效率高?不得不說,這的確是個問題,不過是一個 MySQL 已經考慮到的問題。不錯,挨個遍曆確實效率很低。為了解決這個問題,MySQL 又在頁中加入了另一個區域 Page Directory。

顧名思義,Page Directory是個目錄,裏面有很多個槽位(Slots)
,每一個槽位都指向了一條 User Records中的記錄。大家可以看到,每隔幾條數據,就會創建一個槽位。其實我圖中給出的數據是非常嚴格按照其設定來的,在一個完整的頁中,每隔6條數據就會有一個 Slot。

MySQL 會在新增數據的時候就將對應的 Slot 創建好,有了 Page Directory,就可以對一張頁的數據進行粗略的二分查找
。至於為什麼是粗略,畢竟 Page Directory中不是完整的數據,二分查找出來的結果只能是個大概的位置,找到了這個大概的位置之後,還需要回到 User Records中繼續的進行挨個遍曆匹配。不過這樣的效率已經比我們剛開始聊的原始版本高了很多了。

頁的真實面貌

如果我開篇就把頁的各種組成部分,各種概念直接拋出來,首先我自己接受不了,這樣顯得很僵硬。其次,對頁不熟悉的人應該是不太能理解頁為什麼要這麼設計的。所以我按照查詢一條數據的一套思路,把頁的大致的面貌呈現給了大家。

實際上,頁上還存儲了很多其他的字段,也還有其他的區域,但是這些都不會影響到我們對頁的理解。所以,在對頁有了一個較為清晰的認知之後,我們就可以來看看真實的頁到底長啥樣了。

上圖就是頁的實際全部組成,除了我們之前提到過的,還多了一些之前沒有聊過的,例如 File Header、Page Header、Free Space、File Tailer。

  大家在看