MySQL InnoDB的存儲結構總結

  從物理意義上來講,InnoDB表由共享表空間、日誌文件組(redo文件組)、表結構定義文件組成。若將innodb_file_per_table設置爲on,則系統將爲每一個表單獨的生成一個table_name.ibd的文件,在此文件中,存儲與該表相關的數據、索引、表的內部數據字典信息。表結構文件則以.frm結尾,這與存儲引擎無關。

  以下爲InnoDB的表空間結構圖:

InnoDB存儲引擎中,默認表空間文件是ibdata1,初始化爲10M,且可以擴展,如下圖所示:

  實際上,InnoDB的表空間文件是可以修改的,使用以下語句就可以修改:

Innodb_data_file_path=ibdata1:370Mibdata2:50M:autoextend

  使用共享表空間存儲方式時,Innodb的所有數據保存在一個單獨的表空間裏面,而這個表空間可以由很多個文件組成,一個表可以跨多個文件存在,所以其大小限制不再是文件大小的限制,而是其自身的限制。從Innodb的官方文檔中可以看到,其表空間的最大限制爲64TB,也就是說,Innodb的單表限制基本上也在64TB左右了,當然這個大小是包括這個表的所有索引等其他相關數據

  而在使用單獨表空間存儲方式時,每個表的數據以一個單獨的文件來存放,這個時候的單表限制,又變成文件系統的大小限制了。

  以下即爲不同平臺下,單獨表空間文件最大限度。

Operating System  File-size Limit
Win32 w/ FAT/FAT32  2GB/4GB
Win32 w/ NTFS          2TB (possibly larger)
Linux 2.4+          (using ext3 file system) 4TB
Solaris 9/10          16TB
MacOS X w/ HFS+         2TB
NetWare w/NSS file system  8TB

※ 以下是MySQL文檔中的內容:
Windows用戶請注意: FATVFAT (FAT32)不適合MySQL的生產使用。應使用NTFS

共享表空間與獨佔表空間可以通過參數innodb_file_per_table來轉換,若爲1,則開啓獨佔表空間,否則,開啓共享表存儲。

在服務器資源有限,單表數據不是特別多的情況下獨立表空間明顯比共享方式效率更高 . 但是MySQL 默認是共享表空間 

具體的共享表空間和獨立表空間優缺點如下:

共享表空間:
優點:
可以放表空間分成多個文件存放到各個磁盤上(表空間文件大小不受表大小的限制,如一個表可以分佈在不同步的文件上)。數據和文件放在一起方便管理。
缺點:
所有的數據和索引存放到一個文件中以爲着將有一個很常大的文件,雖然可以把一個大文件分成多個小文件,但是多個表及索引在表空間中混合存儲,這樣對於一個表做了大量刪除操作後表空間中將會有大量的空隙,特別是對於統計分析,日值系統這類應用最不適合用共享表空間。

獨立表空間:在配置文件(my.cnf)中設置: innodb_file_per_table

優點:
1.  每個表都有自已獨立的表空間。
2.  每個表的數據和索引都會存在自已的表空間中。
3.  可以實現單表在不同的數據庫中移動。
4.  空間可以回收(除drop table操作處,表空不能自已回收)
a)         Drop table操作自動回收表空間,如果對於統計分析或是日值表,刪除大量數據後可以通過:alter table TableName engine=innodb;回縮不用的空間。
b)         對於使innodb-pluginInnodb使用truncate table也會使空間收縮。
c)         對於使用獨立表空間的表,不管怎麼刪除,表空間的碎片不會太嚴重的影響性能,而且還有機會處理。
缺點:
單表增加過大,如超過100G

※ 對於啓用了innodb_file_per_table 的參數選項之後,在每個表對應的.idb文件內只是存放了數據、索引和插入緩衝,而撤銷(undo)信息,系統事務信息,二次寫緩衝等還是存放在了原來的共享表空間內。

※ 數據段即B+樹的葉節點,索引段即爲B+樹的非索引節點。

※ InnoDB存儲引擎的管理是由引擎本身完成的,表空間是由分散的頁和段組成。

※ 區由64個連續的頁組成,每個頁大小爲16K,即每個區大小爲1MB,創建新表時,先有32頁大小的碎片頁存放數據,使用完後纔是區的申請,(InnoDB最多每次申請4個區,保證數據的順序性能)

※ 頁類型有:數據頁、Undo頁、系統頁、事務數據頁、插入緩衝位圖頁、以及插入緩衝空閒列表頁



###############################

下面是另一篇相關主題文章

###############################


MySQL Innodb 存儲結構 & 存儲Null值 解析

背景:
 再一次看完<MySQL 技術內幕-Innodb存儲引擎> 一書的的第4章。對前面五節的內容做又有了新的認識,順便做下筆記。先了解下相關的概念:
表空間:INNODB 所有數據都存在表空間當中(共享表空間),要是開啓innodb_file_per_table,則每張表的數據會存到單獨的一個表空間內(獨享表空間)。
獨享表空間包括:數據,索引,插入緩存,數據字典。共享表空間包括:Undo信息(不會回收<物理空間上>),雙寫緩存信息,事務信息等。
段(segment):組成表空間,有區組成。
區(extent):有64個連續的頁組成。每個頁16K,總共1M。對於大的數據段,每次最後可申請4個區。
頁(page):是INNODB 磁盤管理的單位,有行組成。
行(row):包括事務ID,回滾指針,列信息等。

目的1:
瞭解表空間各個頁的信息和溢出行數據存儲的信息。通過該書作者蔣承堯編寫的工具:http://code.google.com/p/david-mysql-tools/source/browse/trunk/py_innodb_page_type/
3個腳本:
py_innodb_page_info.py

複製代碼
#! /usr/bin/env python 
#encoding=utf-8
import mylib
from sys import argv
from mylib import myargv

if __name__ == '__main__':
    myargv = myargv(argv)
    if myargv.parse_cmdline() == 0:
        pass
    else:
        mylib.get_innodb_page_type(myargv)
複製代碼

mylib.py

View Code

include.py

View Code

測試1:

root@localhost : test 02:26:13>create table tt(id int auto_increment,name varchar(10),age int,address varchar(20),primary key (id))engine=innodb;
Query OK, 0 rows affected (0.17 sec)
root@zhoujy:/var/lib/mysql/test# ls -lh tt.ibd 
-rw-rw---- 1 mysql mysql 96K 2012-10-17 14:26 tt.ibd

查看ibd:

複製代碼
root@zhoujy:/home/zhoujy/jiaoben/read_ibd# python py_innodb_page_info.py /var/lib/mysql/test/tt.ibd -v
page offset 00000000, page type <File Space Header>
page offset 00000001, page type <Insert Buffer Bitmap>
page offset 00000002, page type <File Segment inode>
page offset 00000003, page type <B-tree Node>, page level <0000> ---葉子節點
page offset 00000000, page type <Freshly Allocated Page>
page offset 00000000, page type <Freshly Allocated Page>
Total number of page: 6: 
Freshly Allocated Page: 2
Insert Buffer Bitmap: 1
File Space Header: 1
B-tree Node: 1
File Segment inode: 1
複製代碼

解釋:
Total number of page: 總頁數
Freshly Allocated Page:可用頁
Insert Buffer Bitmap:插入緩存位圖頁
Insert Buffer Free List:插入緩存空閒列表頁
B-tree Node:數據頁

Uncompressed BLOB Page:二進制大對象頁,存放溢出行的頁,即溢出頁
上面得到的信息是表初始化大小爲96K,他是有 Total number of page * 16 得來的。1個數據頁,2個可用頁面。

root@localhost : test 02:42:58>insert into tt values(name,age,address) values('aaa',23,'HZZZ');

疑惑:爲什麼沒有申請區?區是64個連續的頁,大小1M。那麼表大小也應該是至少1M。但是現在只有96K(默認)。原因是因爲每個段開始的時候,先有32個頁大小的碎片頁存放數據,使用
完之後纔是64頁的連續申請,最多每次可以申請4個區,保證數據的順序。這裏看出表大小增加是按照至少64頁的大小的空間來增加的,即1M增加。
驗證:
填充數據,寫滿這32個碎片頁,32*16 = 512K。看看是否能申請大於1M的空間。

View Code

"額外"頁:4個
page offset 00000000, page type <File Space Header> :文件頭空間頁
page offset 00000001, page type <Insert Buffer Bitmap>:插入緩存位圖頁
page offset 00000002, page type <File Segment inode>:文件段節點
page offset 00000003, page type <B-tree Node>, page level <0001>:根頁
碎片頁:32個
page type <B-tree Node>, page level <0000>
總共36個頁,ibd大小 576K的由來:32*16=512K(碎片頁)+ 4*16=64(額外頁),這裏開始要是再插入的話,應該申請最少1M的頁:

複製代碼
root@zhoujy:/home/zhoujy/jiaoben/read_ibd# ls -lh /var/lib/mysql/test/tt.ibd 
-rw-rw---- 1 mysql mysql 2.0M 2012-10-17 16:10 /var/lib/mysql/test/tt.ibd
root@zhoujy:/home/zhoujy/jiaoben/read_ibd# python py_innodb_page_info.py /var/lib/mysql/test/tt.ibd
Total number of page: 128:
Freshly Allocated Page: 91
Insert Buffer Bitmap: 1
File Space Header: 1
B-tree Node: 34
File Segment inode: 1
複製代碼

頁從36跳到了128,因爲已經用完了32個碎片頁,新的頁會採用區的方式進行空間申請。信息中看到有很多可用頁,正好說明這點。

 ▲溢出行數據存放:INNODB存儲引擎是索引組織的,即每頁中至少有兩行記錄,因此如果頁中只能存放一行記錄,INNODB會自動將行數據放到溢出頁中。當發生溢出行的時候,實際數據保存在BLOB頁中,數據頁只保存數據的前768字節(老的文件格式),新的文件格式(Barracuda)採用完全行溢出的方式,數據頁只保存20個字節的指針,BLOB也保存所有數據。如何查看錶中有溢出行數據呢?

root@localhost : test 04:52:34>create table t1 (id int,name varchar(10),memo varchar(8000))engine =innodb default charset utf8;
Query OK, 0 rows affected (0.16 sec)

root@localhost : test 04:53:10>insert into t1 values(1,'zjy',repeat('',8000));
Query OK, 1 row affected (0.00 sec)

 查看ibd:

複製代碼
root@zhoujy:/home/zhoujy/jiaoben/read_ibd# python py_innodb_page_info.py /var/lib/mysql/test/t1.ibd -v
page offset 00000000, page type <File Space Header>
page offset 00000001, page type <Insert Buffer Bitmap>
page offset 00000002, page type <File Segment inode>
page offset 00000003, page type <B-tree Node>, page level <0000>
page offset 00000004, page type <Uncompressed BLOB Page>
page offset 00000005, page type <Uncompressed BLOB Page>
Total number of page: 6:
Insert Buffer Bitmap: 1
Uncompressed BLOB Page: 2
File Space Header: 1
B-tree Node: 1
File Segment inode: 1
複製代碼

從信息中看到,剛纔插入的一行記錄,已經溢出了,保存到了2個BLOB頁中(<Uncompressed BLOB Page>)。因爲1頁只有16K,又要存2行數據,所以每行記錄最好小於8K,而上面的遠遠大於8K,所以被溢出了。當然這個也不是包括特大字段,要是一張表裏面有5個字段都是varchar(512)【多個varchar的總和大於8K就可以】,也會溢出:

root@localhost : test 05:08:39>create table t2 (id int,name varchar(1000),address varchar(512),company varchar(200),xx varchar(512),memo varchar(512),dem varchar(1000))engine =innodb default charset utf8;
Query OK, 0 rows affected (0.17 sec)
root@localhost : test 05:08:43>insert into t2 values(1,repeat('',1000),repeat('',500),repeat('',500),repeat('',500),repeat('',500),repeat('阿a',500));

1000+500+500+500+500+500=3500*3>8000字節;行會被溢出:

複製代碼
root@zhoujy:/home/zhoujy/jiaoben/read_ibd# python py_innodb_page_info.py /var/lib/mysql/test/t2.ibd -v
page offset 00000000, page type <File Space Header>
page offset 00000001, page type <Insert Buffer Bitmap>
page offset 00000002, page type <File Segment inode>
page offset 00000003, page type <B-tree Node>, page level <0000>
page offset 00000004, page type <Uncompressed BLOB Page>
page offset 00000000, page type <Freshly Allocated Page>
Total number of page: 6:
Insert Buffer Bitmap: 1
Freshly Allocated Page: 1
File Segment inode: 1
B-tree Node: 1
File Space Header: 1
Uncompressed BLOB Page: 1
複製代碼

<Uncompressed BLOB Page> 頁存放真正的數據,那數據頁到底存放什麼?用hexdump查看:

root@zhoujy:/home/zhoujy/jiaoben/read_ibd# hexdump -C -v  /var/lib/mysql/test/t1.ibd  > t1.txt

查看ibd:

View Code

文本中剛好是48行,每行16字節。48*16=768字節,剛好驗證了之前說的:數據頁只保存數據的前768字節(老的文件格式)。

總結1:
     通過上面的信息,可以能清楚的知道ibd表空間各個頁的分佈和利用信息以及表空間大小增加的步長;特別注意的是溢出行,一個頁中至少包含2行數據,如果頁中存放的行數越多,性能就越好。

************************************
************************************
目的2:
     
瞭解表空間如何存儲數據,以及對NULL值的存儲。

測試2:
在測試前先了解INNODB的存儲格式(row_format)。老格式(Antelope):Compact<默認>,Redumdant;新格式(Barracuda):Compressed ,Dynamic。

這裏測試指針對默認的存儲格式。
Compact行記錄方式如下:

   |變長字段長度列表(1~2字節)|NULL標誌位(1字節)|記錄頭信息(5字節)|RowID(6字節)|事務ID(6字節)|回滾指針(7字節)|

上面信息除了 "NULL標誌位"[表中所有字段都定義爲NOT NULL],"RowID"[表中有主鍵] ,"變長字段長度列表" [沒有變長字段] 可能不存在外,其他信息都會出現。所以一行數據除了列數據所佔用的字段外,還需要額外18字節。

一:字段全NULL

複製代碼
mysql> create table mytest(t1 varchar(10),t2 varchar(10),t3 varchar(10) ,t4 varchar(10))engine=innodb charset = latin1 row_format=compact;
Query OK, 0 rows affected (0.08 sec)

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

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

mysql> insert into mytest values('a',NULL,NULL,'fff');
Query OK, 1 row affected (0.00 sec)
複製代碼

測試數據準備完之後,執行shell命令:

root@zhoujy:/usr/local/mysql/test# hexdump -C -v mytest.ibd > /home/zhoujy/mytest.txt

打開mytest.txt文件找到supremum這一行:

複製代碼
0000c070  73 75 70 72 65 6d 75 6d  03 02 02 01 00 00 00 10  |supremum........|   ----------->一行,16字節
0000c080  00 25 00 00 00 03 b9 00  00 00 00 02 49 01 82 00  |.%..........I...|
0000c090  00 01 4a 01 10 61 62 62  62 62 63 63 63 03 02 02  |..J..abbbbccc...|
0000c0a0  01 00 00 00 18 00 23 00  00 00 03 b9 01 00 00 00  |......#.........|
0000c0b0  02 49 02 83 00 00 01 4b  01 10 61 65 65 65 65 66  |.I.....K..aeeeef|
0000c0c0  66 66 03 01 06 00 00 20  ff a6 00 00 00 03 b9 02  |ff..... ........|
0000c0d0  00 00 00 02 49 03 84 00  00 01 4c 01 10 61 66 66  |....I.....L..aff|
0000c0e0  66 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |f...............|
複製代碼

釋:
第一行數據:
03 02 02 01 /*變長字段*/ ---- 表中4個字段類型爲varchar,並且沒有NULL數據,而且每個字段君小於255。
00 /*NULL標誌位,第一行沒有null的數據*/
00 00 10 00 25 /*記錄頭信息,固定5個字節*/
00 00 00 03 b9 00 /*RowID,固定6個字節,表沒有主鍵*/
00 00 00 02 49 01 /*事務ID,固定6個字節*/
82 00 00 01 4a 01 10 /*回滾指針,固定7個字節*/
61 62 62 62 62 63 63 63 /*列的數據*/
第二行數據和第一行數據一樣(顏色匹配)。
第三行數據(有NULL值)和第一行的解釋的顏色對應起來比較差別:

03 02 02 01  VS  03 01   ----------當值爲NULL時,變長字段列表不會佔用存儲空間。
61 62 62  62 62 63 63 63 VS 61 66 66 66  --------- NULL值沒有存儲,不佔空間

結論:當值爲NULL時,變長字段列表不會佔用存儲空間。NULL值沒有存儲,不佔空間,但是需要一個標誌位(一行一個)。

二:字段全NOT NULL

複製代碼
mysql> create table mytest(t1 varchar(10) NOT NULL,t2 varchar(10) NOT NULL,t3 varchar(10) NOT NULL,t4 varchar(10) NOT NULL)engine=innodb charset = latin1 row_format=compact;
Query OK, 0 rows affected (0.03 sec)

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

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

mysql> insert into mytest values('a',NULL,NULL,'fff');
ERROR 1048 (23000): Column 't2' cannot be null
複製代碼

 步驟和上面一樣,得到的ibd的結果是:

0000c070  73 75 70 72 65 6d 75 6d  03 02 02 01 00 00 10 00  |supremum........|
0000c080  24 00 00 00 03 b9 03 00  00 00 02 49 07 87 00 00  |$..........I....|
0000c090  01 4f 01 10 61 62 62 62  62 63 63 63 03 02 02 01  |.O..abbbbccc....|
0000c0a0  00 00 18 ff cb 00 00 00  03 b9 04 00 00 00 02 49  |...............I|
0000c0b0  08 88 00 00 01 50 01 10  61 65 65 65 65 66 66 66  |.....P..aeeeefff|

和上面比較,發現少了NULL的標誌位信息。
結論:  NULL值會有額外的空間來存儲,即每行1字節的大小。對於相同數據的表,字段中有NULL值的表比NOT NULL的大。

三:1個NULL,和1個''的數據:

複製代碼
mysql> create table mytest(t1 varchar(10) NOT NULL,t2 varchar(10) NOT NULL DEFAULT '',t3 varchar(10) NOT NULL ,t4 varchar(10))engine=innodb charset = latin1 row_format=compact;
Query OK, 0 rows affected (0.02 sec)
mysql> insert into mytest(t1,t2) values('A','BB');
Query OK, 1 row affected, 1 warning (0.01 sec)
複製代碼

 步驟和上面一樣,得到的ibd的結果是:

0000c070  73 75 70 72 65 6d 75 6d  00 02 01 01 00 00 10 ff  |supremum........|
0000c080  ef 00 00 00 43 b9 03 00  00 00 02 4a 15 90 00 00  |....C......J....|
0000c090  01 c2 01 10 41 42 42 00  00 00 00 00 00 00 00 00  |....ABB.........|

和上面2個區別主要在於變長列表和列數據這裏。

結論:列數據信息裏表明了 NULL數據和''數據都不佔用任何空間,對於變長字段列表的信息,和一對比得出:‘’數據雖然不需要佔用任何存儲空間,但是在變長字段列表裏面還是需要佔用一個字節<畢竟還是一個‘’值>,NULL值不需要佔用”,只是NULL會有額外的一個標誌位,所以能有個優化的說法:“數據庫表中能設置NOT NULL的就儘量設置爲NOT NULL,除非確實需要NULL值得。” 在此得到了證明。

上面的測試都是針對VARCHAR的變長類型,那對於CHAR呢?

CHAR 測試:

複製代碼
root@localhost : test 10:33:35>create table mytest(t1 char(10),t2 char(10),t3 char(10) ,t4 char(10))engine=innodb charset = latin1 row_format=compact;Query OK, 0 rows affected (0.16 sec)

root@localhost : test 10:33:59>insert into mytest values('a','bb','bb','ccc');
Query OK, 1 row affected (0.00 sec)

root@localhost : test 10:34:09>insert into mytest values('a','ee','ee','fff');
Query OK, 1 row affected (0.00 sec)

root@localhost : test 10:34:19>insert into mytest values('a',NULL,NULL,'fff');
Query OK, 1 row affected (0.00 sec)
複製代碼

打開ibd生成的文件:

複製代碼
0000c060  02 00 1b 69 6e 66 69 6d  75 6d 00 04 00 0b 00 00  |...infimum......|
0000c070  73 75 70 72 65 6d 75 6d  00 00 00 10 00 41 00 00  |supremum.....A..|
0000c080  00 0a f5 00 00 00 00 81  2d 07 80 00 00 00 32 01  |........-.....2.|
0000c090  10 61 20 20 20 20 20 20  20 20 20 62 62 20 20 20  |.a         bb   |
0000c0a0  20 20 20 20 20 62 62 20  20 20 20 20 20 20 20 63  |     bb        c|
0000c0b0  63 63 20 20 20 20 20 20  20 00 00 00 18 00 41 00  |cc       .....A.|
0000c0c0  00 00 0a f5 01 00 00 00  81 2d 08 80 00 00 00 32  |.........-.....2|
0000c0d0  01 10 61 20 20 20 20 20  20 20 20 20 65 65 20 20  |..a         ee  |
0000c0e0  20 20 20 20 20 20 65 65  20 20 20 20 20 20 20 20  |      ee        |
0000c0f0  66 66 66 20 20 20 20 20  20 20 06 00 00 20 ff 70  |fff       ... .p|
0000c100  00 00 00 0a f5 02 00 00  00 81 2d 09 80 00 00 00  |..........-.....|
0000c110  32 01 10 61 20 20 20 20  20 20 20 20 20 66 66 66  |2..a         fff|
0000c120  20 20 20 20 20 20 20 00  00 00 00 00 00 00 00 00  |       .........|
複製代碼

和一的varchar比較發現:少了變長字段列表,但是對於char來講,需要固定長度來存儲的,存不到固定長度,也會被填充滿。如:20;並且NULL值也不需要佔用存儲空間。

混合(varchar,char):

複製代碼
root@localhost : test 11:21:48>create table mytest(t1 int,t2 char(10),t3 varchar(10) ,t4 char(10))engine=innodb charset = latin1 row_format=compact;
Query OK, 0 rows affected (0.17 sec)

root@localhost : test 11:21:50>insert into mytest values(1,'a','b','c');
Query OK, 1 row affected (0.00 sec)

root@localhost : test 11:22:06>insert into mytest values(11,'aa','bb','cc');
Query OK, 1 row affected (0.00 sec)
複製代碼

 從上面的表結構中看出:
1,變長字段列表長度:1
2,NULL標誌位:1
3,記錄頭信息:5
4,RowID:6
5,事務ID:6
6,回滾指針:7

idb的信息

複製代碼
0000c070  73 75 70 72 65 6d 75 6d  01 00 00 00 10 00 33 00  |supremum......3.| 
0000c080  00 00 0a f5 07 00 00 00  81 2d 1a 80 00 00 00 32  |.........-.....2|
0000c090  01 10 80 00 00 01 61 20  20 20 20 20 20 20 20 20  |......a         |
0000c0a0  62 63 20 20 20 20 20 20  20 20 20 02 00 00 00 18  |bc         .....|
0000c0b0  ff be 00 00 00 0a f5 08  00 00 00 81 2d 1b 80 00  |............-...|
0000c0c0  00 00 32 01 10 80 00 00  0b 61 61 20 20 20 20 20  |..2......aa     |
0000c0d0  20 20 20 62 62 63 63 20  20 20 20 20 20 20 20 00  |   bbcc        .|
複製代碼

從上信息得出和之前預料的一樣:因爲表中只有一個varchar字段,所以,變長列表長度就只有:01 
特別注意的是:各個列數據存儲的信息:t1字段爲int 類型,佔用4個字節的大小。第一行:80 00 00 01 就是表示 1 數字;第二行:80 00 00   0b 表示了11的數字。[select hex(11)  == B ],其他的和上面的例子一樣。

上面都是latin1單字節字符集的說明,那對於多字節字符集的情況怎麼樣?

複製代碼
root@localhost : test 11:52:10>create table mytest(id int auto_increment,t2 varchar(10),t3 varchar(10) ,t4 char(10),primary key(id))engine=innodb charset = utf8 row_format=compact;
Query OK, 0 rows affected (0.17 sec)

root@localhost : test 11:52:11>insert into mytest(t2,t3,t4) values('bb','bb','ccc');
Query OK, 1 row affected (0.00 sec)

root@localhost : test 11:55:34>insert into mytest(t2,t3,t4) values('我們','他們','我們的');
Query OK, 1 row affected (0.00 sec)
複製代碼

 ibd信息如下:

0000c070  73 75 70 72 65 6d 75 6d  0a 02 02 00 00 00 10 00  |supremum........|
0000c080  28 80 00 00 01 00 00 00  81 2d 27 80 00 00 00 32  |(........-'....2|
0000c090  01 10 62 62 62 62 63 63  63 20 20 20 20 20 20 20  |..bbbbccc       |
0000c0a0  0a 06 06 00 00 00 18 ff  c7 80 00 00 02 00 00 00  |................|
0000c0b0  81 2d 28 80 00 00 00 32  01 10 e6 88 91 e4 bb ac  |.-(....2........|
0000c0c0  e4 bb 96 e4 bb ac e6 88  91 e4 bb ac e7 9a 84 20  |............... |

因爲表有了主鍵,所以ROWID(6字節)不見了。
特別注意的是:變長字段列表是3?表裏面的varchar類型的列只有2個啊。經測試得出:在多字節字符集的條件下,char類型被當成可變長度的類型來處理,他們的行存儲基本沒有區別,所以這個就出現變長列表是3了,因爲是utf8字符集,佔用三個字節。所以一個漢字均佔用了一個頁中3個字節的空間(”我們“ :e6 88 91 e4 bb ac)。
數據列的信息:
id列的1值,應該是
80 00 00 01,爲什麼這個顯示00 32 01 10,而且所有的id都是00 32 01 10。測試發現,id爲自增主鍵的時候,id的4個字節長度都是以00 32 01 10 表示。否則和前面一個例子裏說的,用select HEX(X) 表示。

總結2:
     上面的測試都是基於COMPACT存儲格式的,不管是varchar還是char,NULL值是不需要佔用存儲空間的;特別需要注意的是Redumdant的記錄頭信息需要6個固定字節,而NULL值對於varchar來說是不需要佔用存儲空間,對於char來說將會佔用最大值的字節數;在多字節字符集的條件下,CHAR和VARCHAR的行存儲基本是沒有區別的



轉自:http://www.cnblogs.com/benshan/archive/2013/01/08/2851714.html

轉自:http://www.cnblogs.com/zhoujinyi/articles/2726462.html


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章