InnoDB數據頁存儲--施洪寶

一. 簡介

  1. Mysql是目前最爲流行的關係型數據庫管理系統, 具備體積小、速度快、開放源碼等優點。InnoDB是Mysql使用最普遍的存儲引擎, InnoDB進行了行鎖設計, 支持MVCC, 提供一致性非鎖定讀。學習InnoDB數據頁存儲, 可以讓咱們更加深刻的理解InnoDB的一些特性。
  2. 程序 = 數據結構 + 算法, 對於Mysql而言也是如此。因爲數據持久化的須要, Mysql的數據不只存儲在內存中, 也會持久化到文件中, 存儲結構以下圖,

image

  • 從磁盤中, 咱們能夠很容易的看到持久化的各個文件。
  • 磁盤中的文件須要加載到內存中才能被程序使用, 很明顯, 不可能將全部磁盤文件都加載到內存, 當內存中的數據發生更改後, 也須要刷新到磁盤文件中, 何時刷新, 怎麼刷新, 這些都是Mysql須要考慮的問題, 可是這些內容不是本文的重點, 咱們這裏稍加了解便可。
  • 本文的重點是學習數據頁的存儲, 這些數據頁可能存在與系統表空間, 獨立表空間或者臨時表空間。能夠看到, 這些只是圖中的一小部分。
  1. 學習以前, 咱們先考慮幾個問題,
  • 不管是內存存儲仍是磁盤存儲, 都離不開內存管理, InnoDB是如何劃份內存以及如何管理內存的?
  • InnoDB使用B+樹存儲咱們表中的數據, B+樹索引節點以及葉子節點應該須要存儲哪些數據? 又是怎麼存儲的?
  • 咱們在使用時, 建立了數據庫, 數據表, 這些元數據是如何存儲的, 查詢某個表時, 如何根據元數據找到表的索引, 如何選擇索引, 選擇索引後, 如何定位到索引的根節點(root page)? 找到跟節點後, 又是如何一步步找到某個具體數據的?
  1. 說明
  • Mysql版本: 8.0.12-debug
  • 存儲引擎使用InnoDB
  • 咱們會用到xxd命令, 使用xxd(或者hexdump)能夠以十六進制的方式查看文件。

二. InnoDB存儲結構

InnoDB存儲結構圖以下所示, 咱們這裏只作簡要的介紹, 更多細節咱們將在後續的文章中再進行詳細闡述,php

image

  1. 表空間(tablespace)能夠認爲是InnoDB存儲引擎存儲結構的最高層, 全部數據都在表空間中, 除了共享表空間外, 每一個表能夠建立獨立表空間, 具體參數是由innodb_file_per_table參數決定, 表空間由各類段組成。
  2. 常見的段(segment)有數據段, 回滾段, 索引段。innodb中數據段就是B+樹的葉子節點, 索引段就是B+樹中的非葉子節點。
  3. 段是由區(extent)組成, 默認狀況下區的大小是1MB, InnoDB默認頁大小爲16KB, 因此1個區是由16個連續頁組成。
  4. innodb默認頁(page)大小是16KB, 也能夠經過innodb_page_size進行控制。
  5. innodb存儲是面向行(row)的, 行的存儲格式主要有compact、redundant、compressed、dynamic。

三. 數據頁存儲

3.1 獨立表空間

經過innodb_file_per_table參數, 咱們能夠爲每一個表都建立一個表空間, 這個就是這個表的獨立表空間, 這個表的索引段, 數據段都會存儲在這個獨立表空間中, 可是Redo log, Undo log仍然在各自的表空間中, 表空間存儲以下圖, mysql

image

  1. 表空間的page 0是表空間的第一頁, 存儲了表空間的信息, 同時也用於管理前256個extent。page 16384類型爲FIL_PAGE_TYPE_XDES也用於管理以後的256個extent, 以此類推, 每隔16384個頁面都會須要一個FIL_PAGE_TYPE_XDES頁面。
  2. page 1類型是FIL_PAGE_IBUF_BITMAP, 用於管理每一個page(前256個extent的16384個頁面)的change buffer(change buffer相關內容不是本文的重點, 感興趣的讀者能夠查找相關資料)。與FIL_PAGE_TYPE_XDES相似, 每隔16384個頁面都須要一個FIL_PAGE_IBUF_BITMAP頁面。
  3. page 2類型爲FIL_PAGE_INODE, 用於管理segment。
  4. page 3類型爲FIL_PAGE_SDI, 存儲Serialized Dictionary Information(SDI, 詞典序列化信息), 存儲了這個表空間的一些數據字典(Data Dictionary)信息。
  5. page 4通常就是這個表主鍵索引的root page。

3.2 頁存儲

InnoDB的頁存儲結構以下, 每頁都是由3部分組成, File Header(38字節)、File Body、File Trailer(8字節), 不一樣頁的File Body存儲的內容不一樣,算法

image

  1. File Header
名稱 大小 說明
FIL_PAGE_SPACE_OR_CHKSUM 4字節 頁的校驗碼
FIL_PAGE_OFFSET 4字節 表空間中頁的便宜量
FIL_PAGE_PREV 4字節 上一頁
FIL_PAGE_NEXT 4字節 下一頁
FIL_PAGE_LSN 8字節 頁面被最後修改時對應的日誌序列位置
FIL_PAGE_TYPE 2字節 頁面類型
FIL_PAGE_FILE_FLUSH_LSN 8字節 系統表空間中有定義, 表明文件更新到的LSN
FIL_PAGE_ARCH_LOG_NO_OR_SPACE_ID 4字節 頁面所屬表空間id
  1. File Type
名稱 說明
FIL_PAGE_TYPE_ALLOCATED 0x0000 未使用
FIL_PAGE_UNDO_LOG 0x0002 undo log
FIL_PAGE_INODE 0x0003 存儲了段信息
FIL_PAGE_IBUF_FREE_LIST 0x0004 Insert Buffer空閒列表
FIL_PAGE_IBUF_BITMAP 0x0005 Insert Buffer位圖
FIL_PAGE_TYPE_SYS 0x0006 系統頁
FIL_PAGE_TYPE_TRX_SYS 0x0007 事務系統數據
FIL_PAGE_TYPE_FSP_HDR 0x0008 表空間頭部信息
FIL_PAGE_TYPE_XDES 0x0009 擴展描述頁
FIL_PAGE_TYPE_BLOB 0x000A BLOB頁
FIL_PAGE_SDI 0x45bd SDI索引頁
FIL_PAGE_RTREE 0x45be R-tree
FIL_PAGE_INDEX 0x45bf B-tree

3.3 數據頁

看完InnoDB頁結構後, 咱們看下數據頁的存儲,sql

image

  1. Page Header
名稱 大小 說明
PAGE_N_DIR_SLOTS 2字節 page directory中slot的個數
PAGE_HEAP_TOP 2字節 堆中第一個記錄指針
PAGE_N_HEAP 2字節 堆中記錄數
PAGE_FREE 2字節 指向空閒空間首地址
PAGE_GARBAGE 2字節 已經刪除的記錄數
PAGE_LAST_INSERT 2字節 最後插入位置
PAGE_DIRECTION 2字節 最後插入方向
PAGE_N_DIRECTION 2字節 一個插入方向連續插入記錄數
PAGE_N_RECS 2字節 這個頁的記錄總數
PAGE_MAX_TRX_ID 8字節 修改當前頁的最大事務ID
PAGE_LEVEL 2字節 當前頁在索引中的層, 葉子節點爲0x00
PAGE_INDEX_ID 8字節 索引ID
PAGE_BTR_SEG_LEAF 10字節 非葉子節點所在段, 僅在B+樹的root頁中有定義
PAGE_BTR_SEG_TOP 10字節 數據頁所在段, 僅在B+樹的root頁中有定義
  1. Infimun & Supermum

虛擬記錄, Infimum爲13字節, Supermum也是13字節。具體存儲內容, 咱們會在下面進行介紹。數據庫

  1. Page Directory
  • 頁目錄, 由於行記錄在數據頁中以鏈表的形式連接, 可是在查找記錄時, 鏈表查找速度很慢, 爲了加速記錄查找, 建立頁目錄, 頁目錄能夠用於二分查找。每一個目錄項佔用2個字節, 從頁尾部開始, 倒序存儲。
  • 爲了便於理解Page Directory, 咱們這裏舉一個例子, 若是表中存儲了200條數據, 數據經過鏈表的方式進行連接, 咱們在查詢時, 須要遍歷整個鏈表才能找到數據, 這樣無疑比較慢。咱們能夠經過創建索引的方式, 加快查找速度, 咱們能夠將這200條記錄的主鍵按照順序進行存儲, InnoDB的Page Directory就是這個思路, 可是並非存儲了主鍵的值, 而是存儲了對應記錄的位置, 而且不是將每一個行記錄都存儲在Page Directory中, 只是創建一個稀疏索引。

3.4 innodb行存儲

限於篇幅, 咱們這裏主要介紹compact格式的行記錄存儲, 存儲格式以下圖,數據結構

image

  1. 從圖中能夠看出, 每一個記錄行至少佔有5字節(記錄頭) + 主鍵長度 + 6字節(事務ID) + 7字節(回滾指針)
  2. 咱們須要注意記錄頭中的next_record字段, 這個字段佔有16bit, 也就是2個字節, 經過這個字段, InnoDB將一個頁中的全部記錄以鏈表的方式連接到一塊兒。

四. 實例講解

爲了便於你們理解, 這部分咱們給出一些實例,學習

  1. 本節舉例說明InnoDB的一個表是如何存儲的, 主要介紹兩種狀況, 一種狀況是表中數據不多, 另外一種狀況是表中數據比較多, 一頁已經存儲不了的狀況。
  2. 表結構定義,
create table `t` (`id` int not null, primary key(`id`)) engine=InnoDB ROW_FORMAT=Compact;
  • 爲了更容易理解, 咱們這裏只建立了一個很是簡單的表, 也只有一個主鍵索引。主鍵類型爲int, 佔用4個字節。
  • 建立表後, 能夠在相應的目錄下看到t.ibd文件, 這裏我是在test數據庫下建立的這個表, 因此也就在test目錄下。
  • 從磁盤文件中, 咱們能夠看到, t.ibd文件大小爲112KB, 也就是7*16KB, 也就是7個page, 也就意味着, 建立表後, InnoDB默認初始化了7個page。
  • 咱們的表中沒有變長字段, 主鍵長度爲4字節, 因此單個記錄的長度爲5(記錄頭) + 4(主鍵ID) + 6(事務ID) + 7(回滾指針) = 22字節
  1. B+樹示例

InnoDB數據存儲是經過B+樹組織的, 一個很簡單的B+樹以下所示,spa

image

  • B+樹的性質有不少, 其增刪查改操做較常規的二叉樹更復雜一些, 感興趣的能夠查詢相關資料, 這裏有個基本概念便可。
  1. 後續若是沒有特殊說明, 表空間第一個頁是page 0, 第二頁是page 1, 以此類推。

4.1 單頁存儲

咱們首先看下當表中數據不多的時候, 數據是如何組織的, 具體操做步驟以下,debug

  1. 咱們向表中插入2條記錄,
insert into t values (2);
insert into t values (1);
  • 這裏注意咱們先插入主鍵值爲2的行記錄, 再插入主鍵值爲1的行記錄。
  1. 經過xxd將t.ibd以16進製表示, 執行命令xxd t.idb t.txt, 也可使用hexdump命令查看。
  2. 查看t.txt中的內容, 這裏咱們查看page 4的數據
0010000: a76e 6043 0000 0004 ffff ffff ffff ffff  .n`C............
0010010: 0000 0000 012e 6d9d 45bf 0000 0000 0000  ......m.E.......
0010020: 0000 0000 0005 0002 00a4 8004 0000 0000  ................
0010030: 0093 0001 0001 0002 0000 0000 0000 0000  ................
0010040: 0000 0000 0000 0000 0091 0000 0005 0000  ................
0010050: 0002 0272 0000 0005 0000 0002 01b2 0100  ...r............
0010060: 0200 3069 6e66 696d 756d 0003 000b 0000  ..0infimum......
0010070: 7375 7072 656d 756d 0000 10ff f380 0000  supremum........
0010080: 0200 0000 001c 0481 0000 00fa 0110 0000  ................
0010090: 18ff ea80 0000 0100 0000 001c 0582 0000  ................
00100a0: 012c 0110 0000 0000 0000 0000 0000 0000  .,..............
00100b0: 0000 0000 0000 0000 0000 0000 0000 0000  ................
......
......
0013fe0: 0000 0000 0000 0000 0000 0000 0000 0000  ................
0013ff0: 0000 0000 0070 0063 a76e 6043 012e 6d9d  .....p.c.n`C..m.
  • 前38字節是文件頭[0010000,0010026]
  • 以後56字節是數據頁頭部[0010027,001005d]
  • 以後的26字節是最小記錄[001005e, 001006a], 最大記錄[001006b, 0010077], 這裏能夠看到最小記錄的n_owns值爲1(只有自身1條記錄), 最大記錄的n_owns值爲3(除了自身外, 還有咱們插入的兩條記錄)
  • 緊接着是第1條插入記錄[0010078, 001008d]
0010070: .... .... .... .... 0000 10ff f380 0000
0010080: 0200 0000 001c 0481 0000 00fa 0110 ....
  • 最後是剛纔插入的第2條記錄[001008e, 00100a3]
  • 對於int類型, innodb存儲方式與常規的方式不一樣, [0x00000000, 0x7fffffff]表明[-2147483648, -1], [0x80000000, 0xffffffff]表明[0, 21473647]。
  1. 存儲結構以下圖

image

  1. 這裏示例下如何從最小記錄查找到最大記錄
  • 首先定位到最小記錄的位置, 最小記錄佔有5字節(記錄頭) + 8字節(內容) = 13字節, 最小記錄所在的位置爲001005e, 根據最小記錄的記錄頭信息, 能夠計算出下一個記錄所在位置001005e + 0030 = 001008e
  • 001008e是主鍵爲1的記錄所在位置, 接着計算下一個記錄的位置001008e + ffea = 0010078, 這裏須要注意的是, 加法運算時, 只保留後面4位的結果, 能夠看到這個位置就是咱們第一次插入的主鍵爲2的記錄
  • 以後, 繼續計算下一個記錄所在位置, 0010078 + fff3 = 1006b, 這個就是最大記錄所在的位置
  • 在查找某個具體的行記錄時, 能夠先利用page directory進行近似的二分查找, 以後再進行鏈表查找。
  1. page directory
  • 頁尾部包含兩個slots
0013ff0: 0000 0000 0070 0063 .... .... .... ....
  • 0063是第1個slot的位置, 相應的記錄所在位置爲0010063, 也就是最小記錄。[001005e, 0010062]這個是最小記錄的記錄頭, [0010063, 001006a]是最小記錄的內容。
  • 0070是第2個slot的位置, 相應的記錄所在位置爲0010070, 這個是最大記錄所在的內容開始位置。
  1. 小結
  • 能夠看到, 從最小記錄開始, 到最大記錄結束, 數據按照主鍵順序以鏈表的方式進行連接。
  • 行數據的存儲是按照插入的順序存儲的, 不是按照主鍵順序存儲, 數據刪除後, 釋放的空間能夠複用, 關於複用部分的細節, 後續文章再進行詳細介紹。

4.2 多頁存儲

在4.1的基礎上, 咱們繼續插入數據, 操做步驟以下,設計

  1. 咱們經過腳本向表中繼續插入數據
<?php
$servername = "localhost:8083";
$username = "root";
$password = "password";
$dbname = "test";

try {
    $conn = new PDO("mysql:host=$servername;dbname=$dbname", $username, $password);
    $conn->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
    for($i = 3; $i < 1000; $i++){
        $sql = "INSERT INTO t VALUES (" . strval($i) . ")";
        $conn->exec($sql);
    }
}
catch(PDOException $e){
    echo $sql . "<br>" . $e->getMessage();
}
$conn = null;
?>
  • 以前表中已經插入2條記錄, 這裏又插入997條記錄, 因此表中如今一共999條記錄, 主鍵id從1到999。
  • 單條記錄須要佔用22字節, 能夠知道, 此時, 單個數據頁不能存儲所有數據。
  1. 以16進制查看此時的t.ibd文件: xxd t.ibd t.txt
  2. 查看t.txt內容, 首先查看page 4的內容
0010000: df67 193d 0000 0004 ffff ffff ffff ffff  .g.=............
0010010: 0000 0000 0132 5500 45bf 0000 0000 0000  .....2U.E.......
0010020: 0000 0000 0005 0002 0092 8004 0000 0000  ................
0010030: 008a 0002 0001 0002 0000 0000 0000 0000  ................
0010040: 0001 0000 0000 0000 0091 0000 0005 0000  ................
0010050: 0002 0272 0000 0005 0000 0002 01b2 0100  ...r............
0010060: 0200 1a69 6e66 696d 756d 0003 000b 0000  ...infimum......
0010070: 7375 7072 656d 756d 1000 1100 0d80 0000  supremum........
0010080: 0100 0000 0500 0019 ffe6 8000 0153 0000  .............S..
0010090: 0006 0000 0000 0000 0000 0000 0000 0000  ................
.......
.......
0013fe0: 0000 0000 0000 0000 0000 0000 0000 0000  ................
0013ff0: 0000 0000 0070 0063 df67 193d 0132 5500  .....p.c.g.=.2U.
  • 能夠看到, 第5頁, 目前只有少許內容, 由於此時第5頁是索引頁, 是B+樹的根, 沒有存儲具體的數據, 只存儲了主鍵索引。
  • File Header, Page Header, Infimum & Supremum跟以前基本相似, 這裏就再也不詳細介紹。
  • 單個索引須要佔用5字節(記錄頭) + 4字節(主鍵) + 4字節(記錄所在頁) = 13字節。
  • 第1個索引信息
0010070: .... .... .... .... 1000 1100 0d80 0000
0010080: 0100 0000 05.. .... .... .... .... ....

主鍵id爲0x80000001, 也就是1, page no爲0x00000005, 也就是page 5

  • 第2個索引信息
0010080: .... .... ..00 0019 ffe6 8000 0153 0000
0010090: 0006 .... .... .... .... .... .... ....

主鍵id爲0x80000153, 也就是339, page no爲0x00000006, 也就是page 6

  • 經過這兩個索引信息, 能夠知道, page 5存儲着主鍵id從1到338的數據, page 6存儲着主鍵id從339到999的數據
  1. 查看page 5
0014000: e1c0 bb7a 0000 0005 ffff ffff 0000 0006  ...z............
0014010: 0000 0000 0132 5500 45bf 0000 0000 0000  .....2U.E.......
0014020: 0000 0000 0005 0056 3a90 82a6 1d89 1d0c  .......V:.......
0014030: 0000 0005 0000 0152 0000 0000 0000 0000  .......R........
0014040: 0000 0000 0000 0000 0091 0000 0000 0000  ................
0014050: 0000 0000 0000 0000 0000 0000 0000 0100  ................
0014060: 0200 1a69 6e66 696d 756d 0003 000b 0000  ...infimum......
0014070: 7375 7072 656d 756d 0000 1000 1680 0000  supremum........
0014080: 0100 0000 001c 0582 0000 012c 0110 0000  ...........,....
0014090: 1800 1680 0000 0200 0000 001c 0481 0000  ................
00140a0: 00fa 0110 0000 2000 1680 0000 0300 0000  ...... .........
.......
.......
0017e90: 0000 0000 0000 0000 0000 0000 0000 0000  ................
0017ea0: 0000 0000 0070 3a27 39cf 3977 391f 38c7  .....p:'9.9w9.8.
0017eb0: 386f 3817 37bf 3767 370f 36b7 365f 3607  8o8.7.7g7.6.6_6.
0017ec0: 35af 3557 34ff 34a7 344f 33f7 339f 3347  5.5W4.4.4O3.3.3G
0017ed0: 32ef 3297 323f 31e7 318f 3137 30df 3087  2.2.2?1.1.170.0.
0017ee0: 302f 2fd7 2f7f 2f27 2ecf 2e77 2e1f 2dc7  0//././'...w..-.
0017ef0: 2d6f 2d17 2cbf 2c67 2c0f 2bb7 2b5f 2b07  -o-.,.,g,.+.+_+.
0017f00: 2aaf 2a57 29ff 29a7 294f 28f7 289f 2847  *.*W).).)O(.(.(G
0017f10: 27ef 2797 273f 26e7 268f 2637 25df 2587  '.'.'?&.&.&7%.%.
0017f20: 252f 24d7 247f 2427 23cf 2377 231f 22c7  %/$.$.$'#.#w#.".
0017f30: 226f 2217 21bf 2167 210f 20b7 205f 2007  "o".!.!g!. . _ .
0017f40: 1faf 1f57 1eff 1ea7 1e4f 1df7 0070 1d47  ...W.....O...p.G
0017f50: 1cef 1c97 1c3f 1be7 1b8f 1b37 1adf 1a87  .....?.....7....
0017f60: 1a2f 19d7 197f 1927 18cf 1877 181f 17c7  ./.....'...w....
0017f70: 176f 1717 16bf 1667 160f 15b7 155f 1507  .o.....g....._..
0017f80: 14af 1457 13ff 13a7 134f 12f7 129f 1247  ...W.....O.....G
0017f90: 11ef 1197 113f 10e7 108f 1037 0fdf 0f87  .....?.....7....
0017fa0: 0f2f 0ed7 0e7f 0e27 0dcf 0d77 0d1f 0cc7  ./.....'...w....
0017fb0: 0c6f 0c17 0bbf 0b67 0b0f 0ab7 0a5f 0a07  .o.....g....._..
0017fc0: 09af 0957 08ff 08a7 084f 07f7 079f 0747  ...W.....O.....G
0017fd0: 06ef 0697 063f 05e7 058f 0537 04df 0487  .....?.....7....
0017fe0: 042f 03d7 037f 0327 02cf 0277 021f 01c7  ./.....'...w....
0017ff0: 016f 0117 00bf 0063 e1c0 bb7a 0132 5500  .o.....c...z.2U.
  • 注意頁尾部包含page directory, slots的個數能夠從page header中讀取
  • File Header中的FIL_PAGE_NEXT字段, 值爲0x00000006, 也就是page no爲6的頁。
  1. 查看page 6
0018000: 2ddb 788c 0000 0006 0000 0005 ffff ffff  -.x.............
0018010: 0000 0000 0133 f431 45bf 0000 0000 0000  .....3.1E.......
0018020: 0000 0000 0005 00a6 3946 8297 0000 0000  ........9F......
0018030: 3935 0002 0142 0295 0000 0000 0000 0000  95...B..........
0018040: 0000 0000 0000 0000 0091 0000 0000 0000  ................
0018050: 0000 0000 0000 0000 0000 0000 0000 0100  ................
0018060: 0200 1a69 6e66 696d 756d 0006 000b 0000  ...infimum......
0018070: 7375 7072 656d 756d 0000 1000 1680 0001  supremum........
0018080: 5300 0000 001d 6d81 0000 00a3 0110 0000  S.....m.........
.......
.......
001bea0: 0000 0000 0000 0000 0000 0000 0070 38c7  .............p8.
001beb0: 386f 3817 37bf 3767 370f 36b7 365f 3607  8o8.7.7g7.6.6_6.
001bec0: 35af 3557 34ff 34a7 344f 33f7 339f 3347  5.5W4.4.4O3.3.3G
001bed0: 32ef 3297 323f 31e7 318f 3137 30df 3087  2.2.2?1.1.170.0.
001bee0: 302f 2fd7 2f7f 2f27 2ecf 2e77 2e1f 2dc7  0//././'...w..-.
001bef0: 2d6f 2d17 2cbf 2c67 2c0f 2bb7 2b5f 2b07  -o-.,.,g,.+.+_+.
001bf00: 2aaf 2a57 29ff 29a7 294f 28f7 289f 2847  *.*W).).)O(.(.(G
001bf10: 27ef 2797 273f 26e7 268f 2637 25df 2587  '.'.'?&.&.&7%.%.
001bf20: 252f 24d7 247f 2427 23cf 2377 231f 22c7  %/$.$.$'#.#w#.".
001bf30: 226f 2217 21bf 2167 210f 20b7 205f 2007  "o".!.!g!. . _ .
001bf40: 1faf 1f57 1eff 1ea7 1e4f 1df7 1d9f 1d47  ...W.....O.....G
001bf50: 1cef 1c97 1c3f 1be7 1b8f 1b37 1adf 1a87  .....?.....7....
001bf60: 1a2f 19d7 197f 1927 18cf 1877 181f 17c7  ./.....'...w....
001bf70: 176f 1717 16bf 1667 160f 15b7 155f 1507  .o.....g....._..
001bf80: 14af 1457 13ff 13a7 134f 12f7 129f 1247  ...W.....O.....G
001bf90: 11ef 1197 113f 10e7 108f 1037 0fdf 0f87  .....?.....7....
001bfa0: 0f2f 0ed7 0e7f 0e27 0dcf 0d77 0d1f 0cc7  ./.....'...w....
001bfb0: 0c6f 0c17 0bbf 0b67 0b0f 0ab7 0a5f 0a07  .o.....g....._..
001bfc0: 09af 0957 08ff 08a7 084f 07f7 079f 0747  ...W.....O.....G
001bfd0: 06ef 0697 063f 05e7 058f 0537 04df 0487  .....?.....7....
001bfe0: 042f 03d7 037f 0327 02cf 0277 021f 01c7  ./.....'...w....
001bff0: 016f 0117 00bf 0063 2ddb 788c 0133 f431  .o.....c-.x..3.1
  • 注意File Header中的FIL_PAGE_PREV字段, 值爲0x00000005, 也就是page no爲5的頁。
  • 結合page 5能夠看出, 葉子節點的兩個頁經過鏈表進行連接, 每一個頁內的數據經過記錄頭中的next_record字段進行連接。
  1. 存儲結構圖以下,

image

  1. 小結
  • 對於單頁存儲不了的狀況, 須要進行頁分裂, 此時B+樹會有多層結構, 最低層爲葉子節點, 存儲了具體的數據, 上面是索引節點, 只存儲主鍵以及下一層節點所在的頁信息

五. 總結與思考

本文介紹了innodb的數據頁存儲, 以實例的方式講解了innodb存儲引擎如何存儲一個表中數據的。可是咱們仍然有不少問題沒有給出答案,

  1. 查找行記錄時, 須要找到某個索引的root page, 這個信息是存儲在哪裏的?
  2. 咱們沒有介紹段和區的相關內容, 這些在InnoDB數據存儲時是如何使用的?
  3. 咱們查看數據時, 都是直接查看磁盤文件, 內存中的頁與磁盤中的頁有何區別, 內存中的髒頁又是如何刷新到磁盤的?

InnoDB存儲引擎較爲複雜, 不可能一次性將所有內容學會, 咱們不妨每次帶入一個問題, 深刻尋找這個問題的答案, 關於這些問題, 我會在後續文章中再逐步介紹。

六. 參考

  1. <<Mysql技術內幕 InnoDB存儲引擎>>
  2. 淘寶數據庫內核月報
相關文章
相關標籤/搜索