前言 存儲引擎都是把數據存儲在文件系統上,通過通過查詢命令,可以查看數據目錄所在的本機路徑。 mysql> SHOW VARIABLES LIKE 'datadir'; + + + | Variable_name | Value | + + + | datadir | /var/lib/mysql/ ...
存儲引擎都是把數據存儲在文件系統上,通過通過查詢命令,可以查看數據目錄所在的本機路徑。
mysql> SHOW VARIABLES LIKE 'datadir'; +---------------+-----------------+ | Variable_name | Value | +---------------+-----------------+ | datadir | /var/lib/mysql/ | +---------------+-----------------+ 1 row in set (0.00 sec)
每個資料庫都在數據目錄下有一個同名子目錄,這是在新建資料庫時,MySQL自動創建的。在資料庫名對應的子目錄下,每一張數據表都有一個同名以尾碼名為.frm的文件,這個文件存儲了表結構的定義。在InnoDB存儲引擎中,表的數據存儲在一個叫表空間的地方。
InnoDB頁和表的關係
根據表空間的類型可以劃分為如下:
-
系統表空間
InnoDB在數據目錄創建的名為ibdata1的文件,這個文件可以自己擴展大小。一個MySQL進程只有一個系統表空間,其中記錄了一些與整個系統相關的信息。
-
獨立表空間
在資料庫同名的子目錄中,每一張數據表都有一個同名以尾碼名為.ibd的文件。它與.frm文件共同分別存儲了表的結構和記錄。
獨立表空間結構
什麼是區(extent)
表空間中連續的64個頁就是一個區,也就是一個區預設占用1MB空間。無論是系統表空間還是獨立表空間,都可以看成是若幹個連續的區組成,每256個區為一組。
如下extent0-extent255位一組,extent256-extent511位一組,以此類推。
第一組前面3個頁始終是這三種頁:
-
FSP_HDR:用於記錄表空間的一些屬性以及本組所有區的XDES Entry數據結構,也就是有256個。
-
IBUF_BITMAP:存儲Change Buffer的一些信息。
-
INODE:存儲了若幹INODE Entry數據結構。
其餘組前2個頁始終是這兩種:
-
XDES:存儲本組所有區的XDES Entry數據結構。
-
IBUF_BITMAP:同上。
什麼是段(segment)
同一個索引的B+樹結構中,目錄項所在的頁,也就是非葉子節點所在的區的集合為一個段,葉子節點所在的區的集合為一個段。一個索引會生成兩個段,一個葉子節點段和一個非葉子節點段。
表中數據較少時,每次新插入一條記錄,都會被插入到一個碎片區中,當使用了32個碎片區中的頁後,會分配一個完整的區,原先碎片區中的頁不會被覆制到新的完整的區中。因此段是某些零散頁面以及一些完整的區的集合。
什麼是碎片區(fragment)
碎片區也是由64個頁組成,只屬於表空間。結構上和其他的區沒有啥不同。碎片區中的頁用於不同目的,不限制於某個索引的某個段。有些頁屬於段A,有些頁屬於段B。
區的分類
4種類型:
-
空閑的區(FREE)
-
有剩餘空閑頁面的碎片區(FREE_FRAG)
-
沒有剩餘空閑頁面的碎片區(FULL_FRAG)
-
屬於某個段段區(FSEG)
其中FREE、FREE_FRAG和FULL_FRAG獨立且直屬於表空間;FSEG屬於某個段。
什麼是XDES Entry
XDES Entry是一種用於更好管理區的數據結構,每個區都對應一個XDES Entry結構,這個結構存放在每個組都FSP_HDR或XDES頁中。
每個XDES Entry由40個位元組構成,分為4個部分。
-
Segment ID表示所屬段的編號,若不屬於任何段,這個屬性無意義。
-
List Node包含前一個XDES Entry和後一個XDES Entry的指針,通過這些指針可以構成雙向鏈表結構。
-
State的值表示這個區的狀態,也就是FREE、FREE_FRAG、FULL_FRAG或FSEG。
-
Page State Bitmap共16個位元組,合128比特位,沒兩個比特位代表一個頁。其中第1位表示對應的頁是否空閑。
什麼是XDES Entry鏈表
利用XDES Entry中的List Node,將相同類型的區串成雙向鏈表,這麼做的好處是減少隨機I/O,又不至於讓數據少的表浪費空間,避免每次想找到一種類型的區時要遍歷所有的區。
-
FREE鏈表,包含不屬於任何段,且所有頁面都是空閑頁面的區
-
FREE_FRAG鏈表,包含不屬於任何段,且有剩餘空閑頁面的區
-
FULL_FRAG鏈表,包含不屬於任何段,且沒有剩餘空閑頁面的區
屬於某個段的區中會根據List Node串成三種鏈表:
-
FREE鏈表,包含同一個段中,所有頁main都是空閑頁面的區
-
NOT_NULL鏈表,包含同一個段中,存在空閑頁面的區
-
FULL鏈表,包含同一個段中,已經沒有空閑頁面的區
插入記錄流程如下所示:
每一個鏈表的頭節點和尾節點以及這個鏈表中包含了多少個節點的信息被記錄在一個叫List Base Node鏈表基節點的結構中,占用16個位元組。
碎片區中的鏈表基節點存放在FSP_HDR頁中的File Space Header中,附屬於段的鏈表基節點存放在INODE Entry結構中。
什麼是INODE Entry
段不同於區,它是一個邏輯概念,由若幹個零散頁面和一些完整的區組成。與XDES Entry類似,每一個段有一個INODE Entry結構,存放在表空間第一組的INODE頁。
INODE Entry結構如下:
-
Segment ID:段編號
-
NOT_FULL_N_USED:NOT_FULL鏈表中已經使用了頁面數量
-
List Base Node For FREE List:FREE鏈表的基節點。
-
List Base Node For NOTE_FULL List:NOT_FULL鏈表的基節點。
-
List Base Node For FULL List:FULL鏈表的基節點。
-
Magic Number:用來標記這個INODE Entry是否已經被初始化,也就是把各個欄位的信息都填上了。該值為97937874,表明該INODE Entry已被初始化,否則沒有被初始化。
-
Fragment Array Entry:32個,對應著屬於該段的零散頁面的頁號。
直屬於表空間的區,每個區對應一個XDES Entry,根據區的狀態分別建立3個鏈表,鏈表基節點存放在FSD_HDR頁。附屬於段段區,根據頁面空閑狀態,分別建立3個鏈表,鏈表基節點存放在INODE Entry。
什麼是FSP_HDR頁
一個表空間只有一個FSP_HDR頁,其結構如下:
File Header、File Trailer與其他類型的頁類似,主要關註File Space Header和XDES Entry。
-
File Space Header部分
File Space Header結構如下:
-
Space ID欄位表示表空間編號。
-
Size欄位表示當前表空間擁有的頁面數。
-
FREE Limit欄位表示未被初始化的最小頁號。空間增大時,不會立即將空閑空間加入到FREE鏈表,只將一部分加入到FREE鏈表,等FREE鏈表中的XDES Entry對應的區不夠用時,再把沒有加入FREE鏈表的區對應的XDES Entry加入到FREE鏈表,FREE Limit表示還未加入到FREE鏈表的最小頁號。
-
Space Flags表示表空間中的一些狀態屬性。
-
FRAG_N_USED欄位表示FREE_FRAG鏈表中已經使用的頁面數量。
-
List Base Node for FREE List、List Base Node for FREE_FRAG List、List Base Node for FULL_FRAG List著3個欄位分別表示FREE鏈表、FREE_FRAG鏈表和FULL_FRAG鏈表的基節點。使得定位鏈表更容易。
-
NEXT Unused Segment ID欄位表示下一個新建段的ID,類似於自增主鍵。
-
List Base Node for SEG_INODES_FULL欄位表示SEG_INODES_FULL鏈表的基節點。
-
List Base Node for SEG_INDOES_FREE欄位表示SEG_INODES_FREE鏈表的基節點。
-
XDES Entry部分
每個區對應一個XDES Entry結構,一個XDES Entry占用40個位元組,一個組有256個組,表空間第一組中的所有區對應的XDES Entry就存儲在FSP_HDR頁的XDES Entry部分中。
什麼是XDES頁
XDES頁和FSP_HDR頁結構相似,區別在於XDES頁沒有了FIle Space Header部分。功能就是存儲本組中所有區對應的256個XDES Entry。
什麼是IBUF_BITMAP頁
每個組第二個頁都是IBUF_BITMAP,這種類型的頁記錄了有關Change Buffer的東西。
Change Buffer本質是表空間中的一顆B+樹,它的根節點存儲在系統表空間中。在修改非唯一二級索引頁面時,如果該頁尚未被載入到記憶體,那麼該修改將被暫時緩存在Change Buffer中,之後伺服器空閑或載入了該頁到記憶體中,再將修改和冰島該頁面。
什麼是INODE頁
第一個分組中第三個頁面的類型是INODE,其結構如下:
List Node for INODE Page List為前一個INODE頁和後一個INODE頁的指針,每個段對應的INODE Entry結構會急中存放在INODE頁中,每個INODE Entry占用192位元組,一個INODE頁可以存放85個INODE Entry結構。如果表中索引特別多,每個索引對應兩個段,所以一個INODE頁不夠用,就會使用多個INODE頁來進行存儲。這些INODE頁會形成兩個鏈表。
-
SEG_INODES_FULL鏈表:已經沒有空閑空間用來存儲INODE Entry的INODE頁所建立的鏈表。
-
SEG_INODES_FREE鏈表:還有剩餘空間用來存儲INODE Entry的INODE頁所建立的鏈表。
什麼是Segment Header
為了知道某個段對應哪個INODE Entry結構,在段中的記錄所在的頁,也就是INDEX頁Page Header部分有這樣兩個屬性:
名稱 | 大小 | 描述 |
---|---|---|
PAGE_BTR_SEG_LEAF | 10位元組 | B+樹葉子節點段段頭部信息,僅在B+樹段根頁中定義 |
PAGE_BTR_SEG_TOP | 10位元組 | B+樹非葉子節點段的頭部信息,僅在B+樹的根頁中定義 |
這10個位元組對應的是一個Segment Header結構:
名稱 | 大小 | 描述 |
---|---|---|
Space ID for INODE Entry | 4位元組 | INODE Entry結構所在的表空間ID |
Page Number of the INODE Entry | 4位元組 | INODE Entry結構所在的頁面頁號 |
Byte Offset of the INODE Entry | 2位元組 | INODE Entry結構在該頁中偏移量 |
這樣,PAGE_BTR_SEG_LEAF記錄著葉子節點段對應的INODE Entry結構的地址,PAGE_BTR_SEG_TOP記錄著非葉子節點對應的INODE Entry結構的地址。一個索引值對應兩個段,所在只需要在索引的根頁面記錄這兩個結構即可。
閱讀學習自《MySQL是怎樣運行的》小孩子4919