InnoDB行記錄格式

來源:互聯網
上載者:User

InnoDB儲存引擎和大多數資料庫一樣,記錄是以行的形式儲存的。也就是說頁中儲存著表中一行行的資料。在InnoDB 1.0.x版本之前,InnoDB儲存引擎
提供了Compact和Redundant兩種格式來存允許存取記錄資料。
Redundant格式是為了相容之前版本而保留的,如果閱讀過InnoDB的原始碼,使用者會發現原始碼中是用PHYSICAL RECORD(NEW STYLE)和PHYSICAL RECORD(OLD STYLE)來區分兩種格式。
在MySql 5.1版本中,預設設定為Compact行格式。使用者可以通過下面命令查看錶使用的行格式,其中row_format屬性工作表示當前所使用的行記錄結構類型。

mysql> show table status like 'test'\G*************************** 1. row ***************************           Name: test         Engine: InnoDB        Version: 10     Row_format: Compact           Rows: 1 Avg_row_length: 16384    Data_length: 16384Max_data_length: 0   Index_length: 0      Data_free: 5242880 Auto_increment: NULL    Create_time: 2016-07-20 16:13:43    Update_time: NULL     Check_time: NULL      Collation: utf8_general_ci       Checksum: NULL Create_options:         Comment: 1 row in set (0.00 sec)

可以看到test表是Compact的行格式。資料庫執行個體的作用之一就是讀取頁中存放的行記錄。如果使用者自己知道頁中行記錄的組織規則,也可以自行通過編寫工具的方式來讀取其中的記錄。 1、Compact行記錄格式

Compact行記錄是在MySql 5.0中引入的,其設計目標是高效地儲存資料。簡單來說,一個頁中存放的行資料越多,其效能就越高。下面是Compact行記錄的儲存方式:

Compact行記錄格式的首部是一個非NULL變長欄位長度列表,並且其是按照列的順序逆序放置的,其長度是:
(1)若列的長度小於255位元組,用1位元組表示;
(2)若大於255個位元組,用2位元組表示;

變長欄位的長度最大不可以超過2位元組,這是因為在MySql資料中varchar類型的最大長度限制為65535。
變長欄位之後的第二部分是NULL標誌位,該位指示了該行資料中是否有NULL值,有則用1表示。該部分所佔的位元組應該為1位元組。
接下來的部分是記錄頭資訊(record header),固定佔用5位元組(40位),每位的含義如下圖所示:

最後的部分是實際儲存每個列的資料。NULL不佔該部分任何空間,即NULL除了佔有NULL標誌位,實際儲存不佔有任何空間。
另外,每行資料除了使用者定義的列外,還有兩個隱藏列,事務ID列和復原指標列,分別為6位元組和7位元組的大小。若InnoDB表沒有定義主鍵,每行還會增加一個6位元組的rowid列。

接下來用一個具體樣本來分析Compact行記錄的內部結構:

mysql> create table mytest(    -> t1 varchar(10),    -> t2 varchar(10),    -> t3 char(10),    -> t4 varchar(10)    -> )engine=innodb charset=latin1 row_format=compact;Query OK, 0 rows affected (0.09 sec)

下面插入資料:

mysql> insert into mytest values('a','bb','bb','ccc'); Query OK, 1 row affected (0.02 sec)mysql> insert into mytest values('d', 'ee', 'ee', 'fff');Query OK, 1 row affected (0.01 sec)mysql> insert into mytest values('d', NULL, NULL, 'fff');Query OK, 1 row affected (0.01 sec)

查詢表中的資料:

mysql> select * from mytest\G*************************** 1. row ***************************t1: at2: bbt3: bbt4: ccc*************************** 2. row ***************************t1: dt2: eet3: eet4: fff*************************** 3. row ***************************t1: dt2: NULLt3: NULLt4: fff3 rows in set (0.00 sec)

如果啟用了參數innodb_file_per_table,則開啟資料表空間檔案mytest.ibd。否則,開啟預設的共用資料表空間檔案ibdata1,本文中沒有啟用參數innodb_file_per_table,所有開啟檔案ibdata1.

在Linux下,首先找到ibdata1檔案的位置。

root@TryHard:~# find / -name ibdata1;/var/lib/mysql/ibdata1

然後,將二進位檔案ibdata1重新導向為mytest.txt檔案,然後開啟mytest.txt檔案。

root@TryHard:~# hexdump -C -v /var/lib/mysql/ibdata1 > mytest.txt

找到如下圖所示的內容:

下面是對第一行內容進行分析:
03 02 01 是變長欄位長度列表,t1,t2,t3欄位是變長欄位,逆序顯示這三個欄位的長度。插入的資料中t3的值為3個位元組,t2的值為2個位元組,t1的值為1個位元組。
00 是NULL標誌位,為0表示第一行沒有NULL值。
00 00 10 00 2c 是Record Header,固定5位元組長度。
00 00 00 00 09 00 是InnoDB自動建立的rowID,6位元組長度。
兩個隱藏列,事務ID列和復原指標列,分別為6位元組和7位元組的大小。
00 00 00 00 1e 09 是事務ID列,6位元組長度。
8a 00 00 01 3d 01 10 是復原指標列,7位元組長度。
61是t1列的資料’a’;
62 62是t2列的資料’bb’;
62 62 20 20 20 20 20 20 20 是t3列的資料’bb’,t2是固定長度char欄位,如果未用完其佔用的長度空間時,會用0x20來進行填充。
63 63 63是t4列的資料’ccc’;

Record Header的值是00 00 10 00 2c,最後兩個位元組是00 2c,這兩個位元組代表next_recorder,0x2c代表下一個記錄的位移量,即目前記錄的位置加上位移量0x2c就是下一條記錄的起始位置。所以InnoDB儲存引擎在頁內部是通過一種鏈表的結構來串聯各個行記錄的。

第二行和第一行類似 。
下面是第三行的內容:
03 01 變長欄位長度列表,逆序;t1長度為1,t4長度為3,t2和t3為NULL。
06 NULL標誌位,第三行有NULL值。
00 00 20 ff 98 是Record Header;
00 00 00 00 09 02是RowId,6個位元組;
00 00 00 00 1e 0b是事務ID列,6個位元組;
8c 00 00 02 1d 01 10是復原指標列,7個位元組。
64是t1欄位的值’d’;
66 66 66是t4欄位的值’f’;

第三行有NULL值,因為NULL標誌位不再是00而是06,轉換成二進位00000110,為1的值表示第2列和第3列的資料為NULL。其後儲存列資料的部分,沒有儲存NULL列,而只儲存了第1列和第4列的非NULL的值,這也說明了,不管是char還是varchar類型,在compact格式下NULL值都不佔用任何儲存空間。 2、Redundant行記錄格式

Redundant是MySql 5.0版本之前InnoDB的行記錄儲存方式,MySql 5.0支援Redundant是為了相容之前版本的頁格式。Redundant行記錄採用下圖所示的方式儲存。

Redundant行記錄格式的首部是一個欄位長度位移列表,同樣是安裝列的順序逆序存放的。若列的長度小於255位元組,用1位元組表示;若大於255位元組,用2位元組表示。第二個部分為記錄頭資訊(record header),不同於Compact行記錄格式,Redundant行記錄格式的記錄頭佔用6位元組,每位的含義如下圖所示:

其中,n_fields的值代表一行中列的數量,佔用10位,所以能表示的最大值為1023,這也解釋了為什麼MySql資料庫一行支援的最多的列數量為1023。另一個需要注意的值為1byte_offs_flag,該值定義了位移列表佔用1位元組還是2位元組。
最後部分就是實際儲存的每個列的資料了。

建立一個Redundant表mytest2:

mysql> create table mytest2  engine=innodb row_format=redundant  as select * from mytest;Query OK, 3 rows affected (0.04 sec)Records: 3  Duplicates: 0  Warnings: 0

查看錶mytest2資訊:

mysql> show table status like 'mytest2'\G*************************** 1. row ***************************           Name: mytest2         Engine: InnoDB        Version: 10     Row_format: Redundant           Rows: 3 Avg_row_length: 5461    Data_length: 16384Max_data_length: 0   Index_length: 0      Data_free: 5242880 Auto_increment: NULL    Create_time: 2017-03-20 15:46:57    Update_time: NULL     Check_time: NULL      Collation: utf8_general_ci       Checksum: NULL Create_options: row_format=REDUNDANT        Comment: 1 row in set (0.00 sec)

查看資料:

mysql> select * from mytest2\G                       *************************** 1. row ***************************t1: at2: bbt3: bbt4: ccc*************************** 2. row ***************************t1: dt2: eet3: eet4: fff*************************** 3. row ***************************t1: dt2: NULLt3: NULLt4: fff3 rows in set (0.00 sec)

將二進位檔案ibdata1重新導向為mytest.txt檔案,然後開啟mytest.txt檔案。

root@TryHard:~# hexdump -C -v /var/lib/mysql/ibdata1 > mytest.txt

第一行資料:

23 20 16 14 13 0c 06 是長度位移列表,逆序。
00 00 10 0f 00 ba 是Record Header,固定6個位元組;
00 00 00 00 09 0c 是rowId列,6個位元組。
00 00 00 00 1e 1b 是事務ID列,6個位元組。
9a 00 00 01 4b 01 10 是復原指標列,7個位元組。

61 是t1列資料’a’;
62 62是t2列資料’bb’;
62 62 20 20 20 20 20 20 20 20 是t3列資料’bb’, char類型;
63 63 63是t4列資料’ccc’;
23 20 16 14 13 0c 06 逆序為06,0c,13,14,16,20,23,分別代表第一列長度為6,第二列長度為6(6+6 = 0x0c),第三列長度為7(6+6+7=0x13),第四列長度為1(6+6+7+1=0x14),第五列長度為2(6+6+7+1+2=0x16),第六列長度為10(6+6+7+1+2+10=0x20),第七列長度為3(6+6+7+1+2+10+3=0x23).

第1列指的是rowID列,第2列指的是事務ID列,第3列指的是復原指標列,第4列指的是t1,……
在接下來的記錄頭資訊(record Header)中應該注意到48位中的第22-32位,為0000000111,表示表共有7個列(包含了隱藏的3列),接下來的第33位為1,大表位移列表為一個位元組。

後面的資訊就是實際存放的資料。

第三行資料:

21 9e 94 14 13 0c 06 長度位移列表,逆序;
00 00 20 0f 00 74 是Record Header,固定長度為6位元組;
00 00 00 00 09 0e是RowId列;
00 00 00 00 1e 1b 是事務id,6個位元組;
9a 00 00 01 4b 01 2e 是復原指標列,7 個位元組;
64是列t1的資料’d’;
t2類型是varchar,並且值為NULL,所以t2的值不佔用儲存空間。
00 00 00 00 00 00 00 00 00 00 是t3的資料NULL,t3是char類型;
66 66 66是列t4的資料’fff’;

長度位移列表逆序之後得到 06, 0c, 13, 14, 94, 9e, 21,前4個值都好理解。
第5個NULL值變為了94(該列是t2欄位),第6個char類型的NULL值為9e(94+10=0x9e)(該列是t3的欄位),之後的21大表(14+3 = 0x21)。可以看出對於varchar類型的NULL值,Redundant行記錄格式同樣不佔用任何儲存空間,而char類型的NULL值需要佔用空間。

當前表mytest2的字元集為Latin1,每個字元最多隻佔用1個位元組。若使用者將表mytest2的字元集轉換為utf8,第三列char固定長度類型不再是只佔用10位元組了,而是10*3 = 30位元組。

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.