從根兒上理解MySQL | InnoDB存儲結構

目錄

InnoDB記錄結構

變長字段長度列表

NULL值列表

記錄頭信息

InnoDB頁結構

Page Directory(頁目錄)

File Header(文件頭部)

Page Header(頁面頭部)

File Trailer

總結


InnoDB是一個將表中的數據存儲到磁盤上的存儲引擎,而真正處理數據的過程是發生在內存中的,而MySQL中磁盤和內存交互的基本單位,頁的大小一般爲16KB。也就是在一般情況下,一次最少從磁盤中讀取16KB的內容到內存中,一次最少把內存中的16KB內容刷新到磁盤中。

InnoDB記錄結構

這裏以Compact行格式來具體說明:

變長字段長度列表

MySQL支持一些變長的數據類型,比如VARCHAR(M)VARBINARY(M)等,變長字段中存儲多少字節的數據是不固定的,所以我們在存儲真實數據的時候需要順便把這些數據佔用的字節數也存起來。假設某個表中的c1c2c4列都是VARCHAR(10)類型的,存儲的內容分別爲‘aaaa’、‘bbb’、‘d’,並且各個列使用的是ascii字符集,所以每個字符只需要1個字節來進行編碼,則存儲的形式爲:

image_1c9gbruvo504dlg1qsf19nbeu878.png-37kB

需要注意的是,各變長字段數據佔用的字節數是按照列的順序逆序存放,另外,變長字段長度列表中只存儲值爲非NULL的列內容佔用的長度。

NULL值列表

將每個允許存儲NULL的列對應一個二進制位,二進制位按照列的順序逆序排列,值爲1代表該列的值爲NULL,爲0代表不爲NULL。假設c1c3c4這3個列的值都允許爲NULL,其中c3c4的值都爲NULL,所以這3個列對應的二進制位的情況就是,對應的NULL值列表就是06.

記錄頭信息

  • delete_mask

標記記錄是否被刪除,0代表未被刪除,1代表已經被刪除

注:被刪除的記錄會將delete_mask位設置爲1並加入到垃圾鏈表中,而不是立即從磁盤中移除

  • min_rec_mask

標記B+樹的每層非葉子節點中的最小記錄,值爲0表示不是B+樹的非葉子節點中的最小記錄

  • n_owned

每個組的最後一條記錄(組內最大的那條記錄),n_owned屬性表示該組內共有幾條記錄。

  • heap_no

標記記錄在頁中的位置。注:最小、最大記錄(僞記錄)的heap_no分別爲0、1,結構如下圖所示:

  • record_type

標記當前記錄的類型,0表示普通記錄,1表示B+樹非葉節點記錄,2表示最小記錄,3表示最大記錄。

  • next_record

表示從當前記錄的真實數據到下一條記錄的真實數據的地址偏移量,實際上就是一個鏈表。注意:下一條記錄指的是按照主鍵值由小到大的順序的下一條記錄,Infimum記錄(最小記錄) 的下一條記錄就是本頁中主鍵值最小的用戶記錄,而本頁中主鍵值最大的用戶記錄的下一條記錄就是 Supremum記錄(最大記錄)。從下圖中可以看出,記錄按照主鍵從小到大的順序形成了一個單鏈表,最大記錄的next_record的值爲0,是單鏈表中的最後一個結點。

InnoDB頁結構

Page Directory(頁目錄)

頁目錄就是將記錄也製作成一個目錄,將所有正常的記錄(包括最大和最小記錄)劃分爲幾個組,每個組的最後一條記錄的頭信息中的n_owned屬性表示該組內共有幾條記錄,然後將每個組的最後一條記錄的地址偏移量單獨提取出來按順序存儲到靠近頁的尾部的地方,這個地方就是頁目錄,而頁目錄中的這些地址偏移量被稱爲

注意:對每個分組中的記錄條數是有規定的:對於最小記錄所在的分組只能有1條記錄,最大記錄所在的分組擁有的記錄條數只能在1~8條之間,剩下的分組中記錄的條數範圍只能在是4~8條之間

在一個數據頁中查找指定主鍵值的記錄的過程分爲兩步

  1. 通過二分法確定該記錄所在的槽(如想找主鍵值爲6的記錄,(0+4)/2=2 -> (0+2)/2=1 -> 2 ),並找到該槽中主鍵值最小的那條記錄(拿到槽1對應的記錄,該條記錄的下一條記錄);

  2. 通過記錄的next_record屬性遍歷該槽所在的組中的各個記錄。

File Header(文件頭部)

描述了一些針對各種頁都通用的一些信息,比方說這個頁的編號是多少,它的上一個頁、下一個頁, 這個部分佔用固定的38個字節。

對於上面的內容,值得注意的是FIL_PAGE_PREVFIL_PAGE_NEXT分別代表本頁的上一個和下一個頁的頁號(只有索引頁纔有這兩個屬性),這樣就通過建立一個雙向鏈表把許許多多的頁都串聯起來,而無需這些頁在物理上真正連着。也就是說,所有的數據頁其實是一個雙向鏈表

Page Header(頁面頭部)

用於記錄數據頁中存儲的記錄的狀態信息,比如本頁中已經存儲了多少條記錄,第一條記錄的地址是什麼,頁目錄中存儲了多少個槽等等,這部分佔用固定的56個字節,具體在這就不詳述了。

File Trailer

File Trailer的設計是爲了保證從內存中同步到磁盤的頁的完整性,這個部分由8個字節組成,前4個字節代表頁的校驗和,後4個字節代表頁面被最後修改時對應的日誌序列位置(LSN)。在頁的首部和尾部都會存儲頁中數據的校驗和和頁面最後修改時對應的LSN值,如果首部和尾部的校驗和和LSN值校驗不成功的話,就說明同步過程出現了問題。

總結

各個數據頁可以組成一個雙向鏈表,而每個數據頁中的記錄會按照主鍵值從小到大的順序組成一個單向鏈表,每個數據頁都會爲存儲在它裏邊兒的記錄生成一個頁目錄,在通過主鍵查找某條記錄的時候可以在頁目錄中使用二分法快速定位到對應的槽,然後再遍歷該槽對應分組中的記錄即可快速找到指定的記錄。

聲明:本博客純粹爲讀書筆記,如想詳細瞭解MySQL相關知識請訪問《MySQL是怎麼運行的:從根兒上理解MySQL》原作者撰寫資料

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