MyISAM行存儲mysql
MyISAM有3種行存儲格式:fixed/dynamic/compressed;sql
其中fixed爲默認格式,只有當表不包含變長字段(varchar/varbinary/blob/text)時使用,該每行都是固定的,因此很容易獲取行在頁上的具體位置,存取效率比較高,可是佔用磁盤空間較多;oracle
dynamicspa
每行都有一個行頭部,包含bitmap,用以記錄那些列爲空(NULL列不算爲空);指針
相比於fixed,其有以下特性:rest
全部字符串列都是動態存儲的,除非長度小於4;日誌
字符類型若長度爲0/數字類型爲0都會不佔用存儲空間,由bitmap標註,NULL值不包含在內;orm
若是要update行,其擴展後很容易致使行連接既而產生碎片,一旦crash若link丟失則比較難恢復,fixed模式update不會產生碎片;排序
compressed只能經過myisampack建立且爲只讀;索引
MyISAM的索引文件包含一個flag記錄基表是否正常關閉,若是mysqld啓動時指定了--myisam-recover-options,則在打開表時檢測並自動修復表
InnoDB行存儲
Innodb plugin新引入Barracuda梭子魚,其包含compressed/dynamic兩種行格式,而以前的compact/redundant統屬於antelope羚羊;
Barracuda VS antelope
由innodb_file_format(動態)參數決定,目前可選值由Antelope和Barracuda,默認爲前者;要想要此參數生效,
由於共享表空間默認爲Antelope,所以要想使用Barracuda爲默認值,還必須先聲明innodb_file_per_table;
Innodb_file_format用於控制行格式,全局變量可動態調整,5.5默認依舊是Antelope;
下面只看antelope格式
Redundant行結構
字段長度偏移列表 |
記錄頭信息 |
列1數據 |
列2數據 |
…. |
行頭部爲字段長度偏移信息,包括變長和非變長的, 還包含了3個隱藏列:RowID(沒有主鍵時使用)/Transaction ID/Roll Point;而compact只包含變長的,節約了空間;
冗餘行格式沒有NULL標誌位;對於redundant格式,varchar爲Null時不佔用空間,可是char爲NULL須要佔用空間,由於其沒有Null標誌位;
記錄頭信息佔用6個字節,比compact多1字節;
對於定長char,若爲NULL依舊填充整個字段,而varchar爲Null時不佔用空間;
記錄頭信息,與compact相比,多了黑體字部分,缺失record_type
名稱 |
長度bit |
功能 |
Deleted_flag |
1 |
是否被刪除 |
Min_rec_flag |
1 |
1則表示該記錄爲預先被定義的最小記錄 |
N_owned |
4 |
該記錄擁有的總記錄數 |
Heap_no |
13 |
索引中該行的排序記錄 |
N_fields |
10 |
記錄中列數量 |
1byte_offs_flag |
1 |
偏移量列表是1字節仍是2字節 |
Next_recorder |
16 |
下一條記錄相對位置 |
() |
1 |
未知 |
() |
1 |
未知 |
Create table test(t1 varchar(10), t2 varchar(10), t3 char(10),t4 varchar(10)) charset=latin1 row_format=redundant;
--該表有3個變長列
Insert into test values(‘a’,’bb’,’bb’,’ccc’);
使用hexdump –C –v test.idb查看其二進制代碼
--長度偏移列表,
compact行格式
字段長度偏移列表 |
NULL標誌位 |
記錄頭信息 |
列1數據 |
列2數據 |
…. |
5.0引入
行頭存放該行內變長字段的length,當列小於255字節時佔用1個字節,大於255而小於65535時佔用2個字節;故varchar最大長度爲2的16次方-1;
第2個指示該行是否有NULL值,佔用1字節;NULL列不佔用數據存儲空間;
記錄頭信息:5個字節共計40bit,用於連接相鄰的記錄案的行級鎖
名稱 |
長度bit |
功能 |
Deleted_flag |
1 |
是否被刪除 |
Min_rec_flag |
1 |
1則表示該記錄爲預先被定義的最小記錄 |
N_owned |
4 |
該記錄擁有的總記錄數 |
Heap_no |
13 |
索引中該行的排序記錄 |
Record_type |
3 |
行類型 0=普通 1=B+節點指針 |
Next_recorder |
16 |
下一條記錄相對位置 |
() |
1 |
未知 |
() |
1 |
未知 |
除此以外,每頁還有兩個隱含字段:
DB_TRX_ID:6字節,記錄最近的一個事務標示符
DB_ROLL_ID:7字節,指向回滾日誌記錄
--若沒有主鍵,則還會有DB_ROW_ID:6字節,包含在clustered索引中
建立一個compact行格式的表
Create table test(t1 varchar(10), t2 varchar(10), t3 char(10),t4 varchar(10)) row_format=compact;
--該表有3個變長列
Insert into test values(‘a’,’bb’,’bb’,’ccc’);
使用hexdump –C –v test.idb查看其二進制代碼
第一行
03 02 01—變長字段長度列表(逆序),實際順序爲01 02 03,這也是t1,t2,t4的實際長度
00—Null標誌位,第一行沒有NULL
00 00 10 00 2c—記錄頭信息,5字節,後4個字節指向下一個記錄next_recorder
00 00 00 2b 68 00—6字節rowid,由於沒有主鍵
00 00 00 00 06 05 –事務ID,6字節
80 00 00 00 32 01 10—回滾指針,7字節
61 –列1
62 62 –列2
62 62 20 20 20 20 20 20 20 20 –列3,char會填充餘下部分
63 63 63 –列4
餘下的爲列數據,其中t3因爲採用固定長度,故會填充滿10個字節;
第二行
Insert into test values(‘d’,null,null,’fff’);
03 01--變長字段長度列表,逆序
06-- Null標誌位,有NULL值,轉換爲二進制00000110,表示第2/3列爲null
……
64—列1數據
66 66 66—列4數據,而第2/3列爲NULL不佔用存儲空間
注:對於redundant格式,varchar爲Null時一樣不佔用空間,可是char爲NULL須要佔用空間,由於其沒有Null標誌位
行溢出
Innodb表爲IOT,採用了B+數類型,故每一個頁面至少要存儲2行數據,若是行過大則會產生行溢出;
理論上mysql的varchar可存儲65525字節,強於oracle的4000,但對於InnoDB其實際上限爲65532,且該值爲表全部varchar列長度總和;對於utf8字符集,一個字符佔3個字節,則其上限又縮小爲1/3;
若是強行建立varchar(65535)的字段,在sql_mode不爲restricted的狀況下,其會被隱式轉換爲mediumtext;
不管是varchar仍是blob/text,只要保證一個16k的頁面能容下2行數據,應該不會行溢出;
而一旦行溢出,字段前768字節依舊存放於當前頁面,數據通常使用B-tree Node頁,而溢出的行存放於Uncompress Blob頁;
而barracuda採用了徹底行溢出,即只保留字段的前20字節;