您好,登錄后才能下訂單哦!
這篇文章主要講解了“Mysql中InnoDB的行格式詳細介紹”,文中的講解內容簡單清晰,易于學習與理解,下面請大家跟著小編的思路慢慢深入,一起來研究和學習“Mysql中InnoDB的行格式詳細介紹”吧!
我們知道,要處理數據,必須先把數據放到內存中來,那么Mysql讀寫記錄時,是怎么讀寫的勒?Mysql是將數據劃分為若干個頁,以頁作為磁盤和內存之間交互的基本單位,InnoDB中頁的大小一般為 16 KB。也就是在一般情況下,一次最少從磁盤中讀取16KB的內容到內存中,一次最少把內存中的16KB內容刷新到磁盤中。
所謂行格式就是表的一條記錄在磁盤里存儲的二進制格式。迄今為止,InnoDB有四種行格式,分別是Compact、Redundant、Dynamic和Compressed行格式。下面分別介紹下這幾種行格式。
示意圖:
一條記錄存儲分為記錄的額外信息和記錄的真實數據兩部分:
記錄的額外信息又包括變長字段長度列表、NULL值列表、記錄頭信息:
所謂變長字段,指的是如VARCHAR(M)、VARBINARY(M)、各種TEXT類型,各種BLOB類型的字段,變長字段列表主要是存儲的這些字段的真實數據占用的字節長度,該列表的順序是按表字段逆序。在長度列表中每個字段用1-2個字節來其字節長度,具體是1還是2個字節是通過該記錄該字段占用的最大字節長度和真實數據長度來計算得到的。具體規則是:先看字段最大字節長度,小于255直接用1個字節表示,那如果大于255的勒?比如utf8編碼格式下的varchar(100),最大字節長度是3*100=300,超過了一個字節能表示的最大的數。這時應該看真實數據字符占用字節數,如果真實數據字符占用數據字節數小于127,用1個字節,大于用2個字節。為什么是用127做劃分勒,因為一個字節有8位,首位被用來標識需不需要一起讀取下個字節作為字段的字節長度(即這個字段用的是1個字節表示長度還是2個字節)。0需要,1表示不需要。如果碰到該記錄數據字節太長,產生行溢出時(后面會細講),這種情況的話,變長字段長度列表中表示該字段的長度還是2個字節,只表示該記錄在本頁的數據長度。因為2個字節所能表示的字節長度有2的15次方,遠遠大于InnoDb讀寫一頁(16KB)的長度了,所以就算該記錄只有一個字段,本頁數據全存該字段的數據,那2個字節來表示本頁所占長度也是完全放得下的。
注:對于 CHAR(M) 類型的列來說,當列采用的是定長字符集時,該列占用的字節數不會被加到變長字段長度列表,而如果采用變長字符集時,該列占用的字節數也會被加到變長字段長度列表。另外定長字符集下的CHAR類型字段,如果涉及更新或刪除的話,不會產生硬盤碎片,效率比varchar高。
null值列表只有在該記錄所在表的元數據規定有字段可以存在null值才會有null值列表,null值列表是基于位向量來維護字段是否為null的,即用二進制位的0和1表示字段是否為null,該列表也是逆序的。另外InnoDB還規定NULL值列表必須用整數個字節的位表示,如果使用的二進制位個數不是整數個字節,則在字節的高位補0。
記錄頭信息由固定5個字節組成包括:
上圖中,有些概念可能不清楚,后面如果再開文章的話再學習。
記錄的真實數據除了用戶自己定義的列的數據以外,InnoDB還會為每個記錄默認的添加一些列(也稱為隱藏列),具體的列如下:
其中row_id不一定是必須的,只有在表中不存在主鍵的時候InnoDB才會自動添加這列。
示意圖:
這個行格式名稱是也就是Redundant,表示它是已經是過時了的了,現在一般不用,但這里還是介紹一下,對比與Compact的區別。
與變長字段長度列表有兩處不同:
沒有了變長兩個字,意味著Redundant行格式會把該條記錄中所有列(包括隱藏列)的長度信息都按照逆序存儲到字段長度偏移列表。
多了個偏移兩個字,這意味著計算列值長度的方式不像Compact行格式那么直觀,它是采用兩個相鄰數值的差值來計算各個列值的長度。比如每個字段長度按逆序列表的10進制表示是6、12、9,那么偏移之后就是6、18(18-6=12)、27(27-18=9)。
從上面看出,字段長度偏移列表實質上是存儲每個列中的值占用的空間在記錄的真實數據處結束的位置,這種表示方法相對來說更簡單直觀。
注:對于到底用1個字節或2個字節,規則類似Compact,但判斷的是該記錄所有字段真實數據長度,如果真實數據小于127字節,則每個列對應的偏移量占用1個字節,大于127,用兩個字節來劃分,當然真實數據可能超過了2個字節所能表示的最大字節數32767,這時依舊是兩個字節,原因同Compact,2個字節足夠表示該頁的最大偏移(因為1頁就16K,也就是16384個字節),剩下的為溢出列數據,交由其他頁存放,本頁只存其他頁的指向地址。
與Compact的記錄頭信息相比:
Redundant行格式多了n_field和1byte_offs_flag這兩個屬性。
Redundant跟Compact不一樣的是,把是一個或兩個字節表示長度放在了頭信息里面,具體規則類似Compact,但判斷的是該記錄所有字段真實數據長度,如果真實數據小于127字節,則每個列對應的偏移量占用1個字節,大于127(這里可能會疑問為什么是127而不是255(1個字節表示的最大的數),因為與Compact格式不同,Redundant對null值信息沒有集中存儲,而是將字段長度偏移列表首個字節利用起來,標識了該字段為不為null),用兩個字節來劃分,當然真實數據可能超過了2個字節所能表示的最大字節數32767,這時依舊是兩個字節,原因同Compact,2個字節足夠表示該頁的最大偏移(因為1頁就16K,也就是16384個字節),剩下的為溢出列數據,交由其他頁存放,本頁只存其他頁的指向地址。
Redundant行格式沒有record_type這個屬性。
與Compact的區別是:
不會在記錄的真實數據處存儲字段真實數據的前768個字節,而是把所有的字節都存儲到其他頁面中,只在記錄的真實數據處存儲其他頁面的地址。
與Dynamic不同的一點是:
Compressed行格式會采用壓縮算法對頁面進行壓縮,以節省空間。
在我使用的版本Mysql5.7.26版本中,行格式默認為Dynamic。如何進行查看某個表的行格式命令是:
show table STATUS like '表名'
創建或修改表的語句:
CREATE TABLE 表名 (列的信息) ROW_FORMAT=行格式名稱
ALTER TABLE 表名 ROW_FORMAT=行格式名稱
DDL定義時報錯字段溢出
MySQL對一條記錄占用的最大存儲空間是有限制的,除了BLOB或者TEXT類型的列之外,其他所有的列(不包括隱藏列和記錄頭信息)占用的字節長度加起來不能超過65535個字節。如果超過會報ERROR,比如創建一個只有一個字段編碼格式為ascii(1個字節為1個字符)的表:
CREATE TABLE varchar_size_demo( -> c VARCHAR(65535) -> ) CHARSET=ascii ROW_FORMAT=Compact; ERROR 1118 (42000): Row size too large. The maximum row size for the used table type, not counting BLOBs, is 65535. This includes storage overhead, check the manual. You have to change some columns to TEXT or BLOBs
注:這里的65535包含除了列本身的數據之外,還包括一些其他的數據(storage overhead)如NULL值標識(可以為null的字段需要這個標識)、真實數據占用字節的長度。這樣可以計算一下,如果只有一個字段的表,可以為null,那么該字段真實數據可用字節就是65535-2(真實數據占用字節的長度)-1(null值標識)=65532,以上語句可以改為:
CREATE TABLE varchar_size_demo( c VARCHAR(65532) ) CHARSET=ascii ROW_FORMAT=Redundant > OK > 時間: 0.124s
這樣就恰恰夠裝。
運行時的行溢出(不報錯)
在Compact和Reduntant行格式中,對于占用存儲空間非常大的列,在記錄的真實數據處只會存儲該列的一部分數據,把剩余的數據分散存儲在幾個其他的頁中,然后記錄的真實數據處用20個字節存儲指向這些頁的地址(當然這20個字節中還包括這些分散在其他頁面中的數據的占用的字節數),從而可以找到剩余數據所在的頁。如圖:
那么這里怎么計算,產生行溢出的數據長度的臨界點勒?這里與幾個限制有關:
MySQL中規定一個頁中至少存放兩行記錄
一頁只有16K
即只要保證2條數據,加起來數據大小不超過16K減去頁中其他不用于存儲記錄的大小(固定132個字節),就不會產生行溢出,但是一條數據不止有存儲真實數據還有其他。以Compact為例,假設只有1個字段,且可以為Null,則每個記錄需要的額外信息是27字節,包括:
2個字節用于存儲真實數據的長度
1個字節用于存儲列是否是NULL值(不超過255個字段可以為null,所以直接用1個字節)
5個字節大小的頭信息
6個字節的row_id列
6個字節的transaction_id列
7個字節的roll_pointer列
假設一個列中存儲的數據字節數為n,只要滿足:
132 + 2×(27 + n) < 16384
則該記錄不會造成行溢出。當然如果表中有多個字段,上面公式中的27可能會增加(因為“真實數據的長度”和“列是否是NULL值”占用字節可能會增加)。
感謝各位的閱讀,以上就是“Mysql中InnoDB的行格式詳細介紹”的內容了,經過本文的學習后,相信大家對Mysql中InnoDB的行格式詳細介紹這一問題有了更深刻的體會,具體使用情況還需要大家實踐驗證。這里是億速云,小編將為大家推送更多相關知識點的文章,歡迎關注!
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。