Mysql--InnoDB記錄存儲結(jié)構(gòu)

具體細節(jié) 請去掘金購買《MySQL 是怎樣運行的:從根兒上理解 MySQL》

InnoDB頁簡介

  • 1.innodb把數(shù)據(jù)按照頁為基本單位作為與磁盤的交互單位。
  • 2.頁大小一般為16KB

InnoDB行格式

  • 1.記錄是以行格式或者記錄格式存儲在磁盤
  • 2.compact,redundant,dynamic和compressed等四只格式

指定行格式的語法

mysql> CREATE TABLE record_format_demo (
    ->     c1 VARCHAR(10),
    ->     c2 VARCHAR(10) NOT NULL,
    ->     c3 CHAR(10),
    ->     c4 VARCHAR(10)
    -> ) CHARSET=ascii ROW_FORMAT=`COMPACT`;
Query OK, 0 rows affected (0.03 sec)

COMPACT行格式

  • 1.主要是兩部分:記錄的額外信息和記錄的真實數(shù)據(jù)。
  • 2.額外信息:變長字段長度列表,NULL值列表,記錄頭信息
  • 3.真實數(shù)據(jù):各個列的值。

變長字段長度列表

  • 1.VARCHAR(M)、VARBINARY(M)、各種TEXT類型,各種BLOB類型.
  • 2.對于變長的字段,mysql存儲其真實數(shù)據(jù)內(nèi)容和占用的字節(jié)數(shù)。
  • 3.Compact行格式中,所有變長字段的占用的字節(jié)長度放在開頭形成鏈表,是逆序存放(比如列a,列b,則鏈表就是ba)
  • 4.如果該可變字段允許存儲的最大字節(jié)數(shù)(M×W)超過255字節(jié)并且真實存儲的字節(jié)數(shù)(L)超過127字節(jié),則使用2個字節(jié),否則使用1個字節(jié)。
  • 5.該字節(jié)的第一個二進制位作為標志位:如果該字節(jié)的第一個位為0,那該字節(jié)就是一個單獨的字段長度(使用一個字節(jié)表示不大于127的二進制的第一個位都為0),如果該字節(jié)的第一個位為1,那該字節(jié)就是半個字段長度。
  • 6.變長字段長度列表中只存儲值為 非NULL 的列內(nèi)容占用的長度,值為 NULL 的列的長度是不儲存的

NULL值列表

  • 1.把列中的存儲NULL的都放入列表中,這樣就不需要再真實數(shù)據(jù)中占有地方
  • 2.如果所有列都沒有允許存儲NULL 則NULL值列表不存在。
  • 3.將允許存儲NULL的列表采用二進制位表示,0表示該列值不為NULL,1則是NULL。注意是逆序。
  • 4.規(guī)定了列表表示的二進制必須是整數(shù)個字節(jié),如果NULL值列不夠8則 高位設置為0補齊。

記錄頭信息

  • 1.由固定的5個字節(jié)組成,40個位可以表示40個不同的意思

記錄的真實數(shù)據(jù)

  • 1.除了正常的列信息之外,還會包含一些隱藏列
  • 2.row_Id(如果不存在主鍵或者其他的唯一索引,則有該列)
  • 3.tracsaction_id(事務id)
  • 4.roll_pointer,指向了歷史記錄,可以幫助回滾和實現(xiàn)MVCC

CHAR(M)列的存儲格式

  • 1.當char列采用的是定長字符集時候,該列占用的字節(jié)數(shù)不會被加到變長字段長度列表,否則會加入
  • 2.比如采用了ascii就不需要加入,采用UTF-8就需要加入
  • 3.變長字符集的CHAR(M)類型的列要求至少占用M個字節(jié),比如我們采用UTF-8編碼CHAR(10),那么字節(jié)長度可能為10-30,所以我們存入空字符也會占用10個字節(jié)
  • 4.上述的好處是如果記錄更新,可以直接利用該存儲空間,無需重新分配。(當然如果如果更新記錄超過10個字節(jié)還是需要重新開辟)

注意了在Compact行格式下,Mysql的列有變長類型,同時對列的編碼字符集也有動態(tài)的,只有是定長類型的列并且也采用定長類型的編碼列,占用分配空間大小才固定。

Redundant行格式

  • 1.主要是兩部分:記錄的額外信息和記錄的真實數(shù)據(jù)。
  • 2.額外信息:字段長度偏移列表,記錄頭信息
  • 3.記錄的真是數(shù)據(jù)。

字段長度偏移列表

  • 1.記錄所有字段包含隱藏列的長度信息,逆序。

記錄頭信息

  • 1.Redundant行格式多了n_field和1byte_offs_flag這兩個屬性。
  • 2.Redundant行格式?jīng)]有record_type這個屬性。
  • 3.1byte_offs_flag:標記字段長度偏移列表中每個列對應的偏移量是使用1字節(jié)還是2字節(jié)表示的
  • 4.1byte_offs_flag的值是怎么選擇的:根據(jù)該條Redundant行格式記錄的真實數(shù)據(jù)占用的總大小來判斷的:當記錄的真實數(shù)據(jù)占用的字節(jié)數(shù)不大于127(十六進制0x7F,二進制01111111)時,每個列對應的偏移量占用1個字節(jié)
    ,當記錄的真實數(shù)據(jù)占用的字節(jié)數(shù)大于127,但不大于32767(十六進制0x7FFF,二進制0111111111111111)時,每個列對應的偏移量占用2個字節(jié)。
    大于32767的情況存放到了溢出頁中
  • 5.在Redundant行格式下 多余字節(jié)存放溢出頁,在本頁只保留前768個字節(jié)和20個字節(jié)的溢出頁面地址,因此只需要2個字節(jié)記錄偏移量

Redundant行格式中NULL值的處理

  • 1.因為Redundant行格式并沒有NULL值列表
    1. 將列對應的偏移量值的第一個比特位作為是否為NULL的依據(jù),該比特位也可以被稱之為NULL比特位
  • 3.正是因為首位被做Null比特位了所以才在大于127的時候使用2個字節(jié)來記錄長度
  • 4.如果NULL列采用定長字符集來存儲,則采用0x00字節(jié)填充,如果是變長則不占用任何存儲空間

CHAR(M)列的存儲格式

  • 1.Compact行格式在CHAR(M)類型的列中存儲數(shù)據(jù)的時候還挺麻煩,分變長字符集和定長字符集的情況
  • 2.而在Redundant行格式中十分干脆,不管該列使用的字符集是啥,只要是使用CHAR(M)類型,占用的真實數(shù)據(jù)空間就是該字符集表示一個字符最多需要的字節(jié)數(shù)和M的乘積
  • 3.因此不會產(chǎn)生碎片

行溢出數(shù)據(jù)

  • 1.除了BLOB或者TEXT類型的列之外,其他所有的列(不包括隱藏列和記錄頭信息)占用的字節(jié)長度加起來不能超過65535個字節(jié)
  • 2.這個65535個字節(jié)除了列本身的數(shù)據(jù)之外,還包括一些其他的數(shù)據(jù)(storage overhead),比如說我們?yōu)榱舜鎯σ粋€VARCHAR(M)類型的列,其實需要占用3部分存儲空間:
    真實數(shù)據(jù)
    真實數(shù)據(jù)占用字節(jié)的長度
    NULL值標識,如果該列有NOT NULL屬性則可以沒有這部分存儲空間
  • 3.如果該VARCHAR類型的列沒有NOT NULL屬性,那最多只能存儲65532個字節(jié)的數(shù)據(jù)
  • 4.Compact和Reduntant行格式中,對于占用存儲空間非常大的列,在記錄的真實數(shù)據(jù)處只會存儲該列的一部分數(shù)據(jù)
  • 5.記錄的真實數(shù)據(jù)處用20個字節(jié)存儲指向這些頁的地址,這些也采用鏈表進行連接。
  • 6.不只是 VARCHAR(M) 類型的列,其他的 TEXT、BLOB 類型的列在存儲數(shù)據(jù)非常多的時候也會發(fā)生行溢出。

行溢出的臨界點

  • 1.MySQL中規(guī)定一個頁中至少存放兩行記錄

Dynamic(5.7默認)和Compressed行格式

  • 1.Dynamic和compact很相似,處理行溢出數(shù)據(jù)時有點兒分歧,只記錄地址,不會記錄部分真實數(shù)據(jù)。
  • 2.Compressed行格式和Dynamic不同的一點是Compressed行格式會采用壓縮算法對頁面進行壓縮,以節(jié)省空間。
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容