概念
在 InnoDB 存儲引擎中,所有的資料都被邏輯地存放在表空間中,表空間(tablespace)是存儲引擎中最高的存儲邏輯機關,在表空間的下面又包括段(segment)、區(extent)、頁(page),他們之間的關系如下:
資料頁
頁是mysql中磁盤和記憶體交換的基本機關,也是mysql管理存儲空間的基本機關。
同一個資料庫執行個體的所有表空間都有相同的頁大小;預設情況下,表空間中的頁大小都為 16KB,當然也可以通過改變 innodb_page_size 選項對預設大小進行修改,需要注意的是不同的頁大小最終也會導緻區大小的不同。
一次最少從磁盤讀取16KB内容到記憶體中,一次最少把記憶體中16KB内容重新整理到磁盤中,當然了單頁讀取代價也是蠻高的,一般都會進行預讀
名稱 | 中文名 | 占用空間大小 | 簡單描述 |
| 檔案頭部 | 38位元組 | 頁的一些通用資訊 |
| 頁面頭部 | 56位元組 | 資料頁專有的一些資訊 |
+ | 最小記錄和最大記錄 | 26位元組 | 兩個虛拟的行記錄 |
| 使用者記錄 | 不确定 | 實際存儲的行記錄内容 |
| 空閑空間 | 不确定 | 頁中尚未使用的空間 |
| 頁面目錄 | 不确定 | 頁中的某些記錄的相對位置 |
| 檔案尾部 | 8位元組 | 校驗頁是否完整 |
Infimum + Supremum
- 這個值位于整個頁面的第三部分
- 分别是最小記錄和最大記錄,屬于MySQL為每個頁添加的
虛拟記錄
- 由五個位元組的
和 八個位元組的 值(分别是單詞記錄頭
和Infimum
)組成Supremum
- 最小記錄的記錄頭中
為0heap_no
- 最大記錄的記錄頭中
為1heap_no
- 也就是說正式記錄中的
屬性從2開始heap_no
- 最小記錄的record_type 是2
- 最大記錄的record_type 是3
- 最小記錄是頁中單連結清單的頭結點
- 最大記錄是頁中單連結清單的尾結點
Page Directory
Page Directory
- 這個頁目錄裡面存的是一個一個的槽(
)slot
- 每個槽指向組内最大記錄的位址偏移量(我了解為頁内偏移量)
- 這個資料結構是數組,按主鍵值從小到大排列
- 這種結構注定了查詢最快的方式是二分法,時間複雜度O(lgN)
-
(前面說過) 時會增加一個槽頁分裂
User Records
和
Free Space
- 完全空閑的頁是沒有
部分的User Records
- 插入資料時,從
配置設定空間給Free Space
,直到User Records
沒有空間或空間不夠配置設定新的記錄,這時需要申請新的頁Free Space
Page Header
名稱 | 占用空間大小 | 描述 |
| 2位元組 | 在頁目錄中的槽數量 |
| 2位元組 | 還未使用的空間最小位址,也就是說從該位址之後就是Free Space |
| 2位元組 | 本頁中的記錄的數量(包括最小和最大記錄以及标記為删除的記錄) |
| 2位元組 | 第一個已經标記為删除的記錄位址(各個已删除的記錄通過next_record也會組成一個單連結清單,這個單連結清單中的記錄可以被重新利用) |
| 2位元組 | 已删除記錄占用的位元組數 |
| 2位元組 | 最後插入記錄的位置 |
| 2位元組 | 記錄插入的方向 |
| 2位元組 | 一個方向連續插入的記錄數量 |
| 2位元組 | 該頁中記錄的數量(不包括最小和最大記錄以及被标記為删除的記錄) |
| 8位元組 | 修改目前頁的最大事務ID,該值僅在二級索引中定義 |
| 2位元組 | 目前頁在B+樹中所處的層級 |
| 8位元組 | 索引ID,表示目前頁屬于哪個索引 |
| 10位元組 | B+樹葉子段的頭部資訊,僅在B+樹的Root頁定義 |
| 10位元組 | B+樹非葉子段的頭部資訊,僅在B+樹的Root頁定義 |
1.
PAGE_GARBAGE
- 在頁面空間不夠時,會嘗試将所需空間與這個值比較,如果夠,那麼将記錄移到臨時表中,再重新插回來(記錄逐條新增是不會産生碎片空間的),但很明顯,這很耗性能
-
和 PAGE_BTR_SEG_LEAF
PAGE_BTR_SEG_TOP
- 後面會說到段的概念,一個索引會有兩個段,一個葉子節點段,一個非葉子節點段,這兩個屬性分别代表一個
,代表了哪個表空間哪個頁面的哪個Segment Header
(表空間号 + 頁面号 + 偏移量值)INODE Entry
File Header
名稱 | 占用空間大小 | 描述 |
| 4位元組 | 頁的校驗和(checksum值) |
| 4位元組 | 頁号 |
| 4位元組 | 上一個頁的頁号 |
| 4位元組 | 下一個頁的頁号 |
| 8位元組 | 頁面被最後修改時對應的日志序列位置(英文名是:Log Sequence Number) |
| 2位元組 | 該頁的類型 |
| 8位元組 | 僅在系統表空間的一個頁中定義,代表檔案至少被重新整理到了對應的LSN值 |
| 4位元組 | 頁屬于哪個表空間 |
這個屬性裡面的值就說三個:
-
FIL_PAGE_OFFSET
- 每個表空間的頁号唯一,四個位元組足夠用了
-
和 FIL_PAGE_PREV
FIL_PAGE_NEXT
- 上一頁和下一頁,诶喲,這不是雙向連結清單啊,那所有的頁加起來組成了一個雙向連結清單哇,好玩吧~
-
FIL_PAGE_TYPE
類型名稱 | 十六進制 | 描述 |
| 0x0000 | 最新配置設定,還沒使用 |
| 0x0002 | Undo日志頁 |
| 0x0003 | 段資訊節點 |
| 0x0004 | Insert Buffer空閑清單 |
| 0x0005 | Insert Buffer位圖 |
| 0x0006 | 系統頁 |
| 0x0007 | 事務系統資料 |
| 0x0008 | 表空間頭部資訊 |
| 0x0009 | 擴充描述頁 |
| 0x000A | BLOB頁 |
| 0x45BF |
- 假設一條查詢語句定位到了這個頁面
- 先将條件中的列(加深為
)與值(假設為col
)拎出來,二分法定位在哪個組。x
- 假設10個槽,(0 + 9)/2 = 4, 将第四個槽的條件列的值拿出來跟
比較,如果x
大,那就從5~9的槽中繼續二分找;如果x
小, 那就從0~4的槽中繼續二分;x
- 直到前後兩個槽相差為1,那記錄就在那個大的槽裡面,又每個槽其實存的是組内最大記錄,那前一個槽對應記錄的下一個節點就是目标槽對應組中的最小值,順着單連結清單往後一個一個比就完事了,每組最多八條記錄,這速度還是很快的。