1. 程式人生 > 其它 >12.Innodb資料頁的結構01

12.Innodb資料頁的結構01

1.前言

  在innodb中頁是儲存空間的基本單位,一個頁的大小一般是16kb。innodb為了不同的目的而設計了多種不同型別的頁,比如存放表空間頭部資訊的頁,存放change buffer資訊的頁,存放inode資訊的頁,儲存undo日誌資訊的頁等等,這裡這要說說存放表中記錄的那種型別的頁,官方稱這種存放記錄的頁為索引(index)頁,有時候也會稱之為資料頁。

上圖就是innodb資料頁結構的示意圖

2.頁儲存著記錄

  在上面7個部分中,我們自己的資料(記錄)會按照指定的行格式儲存到User Records部分。但是在一開始生成頁的時候,其實並沒有User Records部分,每當插入一條記錄時,都會從Free Space部分(也就是尚未使用的儲存空間)申請一個記錄大小的空間,並將這個空間劃分到User Records部分。當Free Space部分的空間全部被User records部分替代掉之後,也就意味著這個頁使用完了,此時如果還有新的記錄插入,就需要申請新的頁了。

  2.1 記錄頭資訊

  由於頁中儲存的都是記錄,因為在瞭解頁之前,我們先看看記錄,而關於記錄在上一節的行格式中已經提到了,一條記錄主要是由記錄額外資訊和記錄真實資訊兩部分組成,其中記錄真實資訊就是我們所看到的各個列下面的資料(這個就很簡單了),那麼主要說說記錄額外資訊了,關於記錄額外額外資訊主要有1)變長欄位欄位長度列表 2)NULL值 3)記錄頭資訊三部分組成,其中關於1和2這裡就不說了,主要就看3中所謂的記錄頭資訊。

  看如下結構如下:

  各個屬性解釋:

名稱 大小 描述
預留位1 1 沒有使用
預留位2 1 沒有使用
delete_flag 1 標記該記錄是否被刪除
min_rec_flag 1 B+樹中每層非葉子節點中的最小的目錄項記錄都會新增該標記
n_owned 4 一個頁面中的記錄會被分成若干組,每個組中的記錄有一個"
帶頭大哥",其餘記錄都是“小弟”。“帶頭大哥”記錄的n_owned
值代表該組中所有的記錄條數,"小弟"記錄的n_owned都是0
heap_no 13 表示當前記錄在頁面堆中的相對位置
record_type 3 表示當前記錄的型別,0表示普通記錄,1表示B+樹非葉子節點
的目錄項記錄,2表示infimum記錄,3表示Supremum記錄
next_record 16 表示下一條記錄的相對位置

這裡模擬一下幾條記錄,介紹一條記錄按照如下格式進行記錄的話:

這裡有4條記錄,按照上面的記錄格式進行填寫的

  • delete_flag:這個屬性用來標記當前記錄是否被刪除,佔用1位元。值為0時表示記錄沒有被刪除,值為1時表示記錄已經被刪除。對應這個屬性來說,它只是進行對記錄進行標記,因此當我們對一條記錄delete操作時,其實只是對這條記錄做了一個刪除的標記,並沒有真正的從磁碟上進行刪除。這些被刪除的記錄之所以不從磁碟上刪除,是因為移除了它們之後,還需要在磁碟上重新排列其他記錄,這就會帶來效能上的消耗,所以只打一個刪除標記就能避免這個問題。另外所有被刪除掉的記錄會組成一個垃圾連結串列,記錄在這個連結串列中佔用的空間稱為可重用空間,之後若有新的記錄插入到表中,它們就可能覆蓋掉被刪除的這些記錄佔用的空間。  
  • heap_no:我們向表中插入的記錄從本質上來說都是放到資料頁的User Records部分,這些記錄一條一條地親密無間地排列著,innodb的設計者把記錄一條一條親密無間排列的結構稱之為堆(heap).為了方便管理這個堆,它們把一條記錄的在堆中的相對位置稱之為heap_no.在頁面前邊的記錄heap_no相對較小。在頁面後面的記錄heap_no相對較大,每新申請一條記錄的儲存空間時,該條記錄比物理位置在它前面的那條記錄的heap_no值大1.另外一點需要注意的是,堆中記錄的heap_no值在分配之後就不發生改動了,即使之後刪除了堆中的某條記錄,這條被刪除記錄的heap_no值也仍然保持不變。
  • recore_type:這個屬性表示當前記錄的型別,一共是4中型別的記錄,其中0表示普通記錄。1表示B+樹非葉子節點的目錄項記錄,2表示infimum記錄,3表示Supremum記錄
  • next_record:這個屬性非常重要,它表示從當前記錄的真實資料到下一條記錄的真實資料的距離。如果該屬性值為正數,說明當前記錄的下一條記錄在當前記錄的後面,如果該屬性值為負數,說明當前記錄的下一條記錄在當前記錄的前面,比如,第1條記錄的next_record值為32,意味著從第1條記錄的真實資料的地址處向後找32位元組便是下一條記錄。在比如,第四條的next_record值為-111,意味著從第4條記錄的真實資料的地址處向前找111位元組便是下一條記錄的真實資料,這個有點類似於連結串列,可以通過一條記錄找到下一條記錄。

  這裡使用箭頭替代next_record的值,從上圖可以看出,記錄按照主鍵從小到大的順序形成一個單向連結串列。Supremum記錄的next_record值為0,也就是說Supremum記錄之後就沒有下一條記錄了,這也意味著Supremum記錄就是這個單向連結串列中的最後一個節點,如果從表中刪除一條記錄,這個由記錄組成的單向連結串列也是會跟著變化。

所以無論怎麼對頁中的記錄進行增刪改查操作,innodb始終會維護記錄的一個單向連結串列,連結串列中的各個節點是按照主鍵值由小到大的順序連結起來的。

這裡再看一個有意思的地方:主鍵值為2的記錄被刪除掉了,但是卻沒有回收儲存空間(該記錄的heap_no也未發生改變),如果我們在把這條記錄插入到表中,會發生什麼呢?

這裡可以看到,innodb並沒有因為新的記錄的插入而為它申請新的儲存空間,而是直接複用了原理被刪除記錄的儲存空間。