今天開發在導入數據的時候報一個錯誤:
Row size too large. The maximum row size for the used table type, not counting BLOBs, is 8126. You have to change some columns to TEXT or BLOBs
原因:發現導入的數據單行長度較長。
官方文檔的解決辦法為:
1.垂直表字段拆分或者大字段合並(大字段最多不超過768,業務進行合並+拆分),divide your table into small ones. If one table contain more than 10 text colums, and the data contain is a little bit long. this error will be thrown out.
2.修改表的存儲引擎,modify InnoDB to MyISAM.
3.修改row_format為COMPRESSED或者DYNAMIC,當然前提需保證innodb_file_format =Barracuda.
但為什么會出現上面的解釋?
通過查詢發現為innodb的一個限制:
我們知道innodb的頁塊大小默認為16kb,表中數據是存放在B-tree node的頁塊中,但如果表中一行的數據長度超過了16k,這時候就會出現行溢出,溢出的行是存放在另外的地方,存放該溢出數據的頁叫uncompresse blob page。
innodb采用聚簇索引的方式把數據存放起來,即B+樹結構,因此每個頁塊中至少有兩行數據,否則就失去了B+樹的意義(每一個頁中只有一條數據,整個樹成為了一條雙向鏈表),這樣就得出了一行數據的最大長度就限制為了8k。
當插入的一行數據不能在一個數據頁塊中存放時,為了保證該頁至少能存放兩行數據,innodb將會自動部分數據溢出到另外頁中,一部分數據將存放在數據頁塊中,其大小為該列的前768字節,同時接着還有偏移指向溢出頁。
如上面所說大字段的前768字節會存放在數據頁塊中,那么如果有10個大字段(如varchar(1000),text,blob同varchar同樣存儲前768字節),同樣會超過一行數據8k的限制(10*768<8000,11*768>8000)。如果插入的值超過8000字節,則會報錯(BLOB或TEXT同理):
測試如下:
表結構:

插入10列數據(10*768<8000)可以插入:


插入11列數據(11*768>8000)報錯:

Text數據類型測試:


Blob數據類型測試:


明白了是怎么一回事后,就可以解決出現問題了,減少varchar(1000)的字段數量,或者改存儲引擎為myisam;還可以增加page_size的大小:如改為32k,64k。由於需求不好改動,數據庫的頁塊大小改變需要改動源碼,了解該表以查詢為主,更新非常少,所以改為myisam存儲引擎:
可以看到myisam存儲引擎不受此限制。

從上面也可以看出,在mysql innodb存儲引擎表收到頁塊大小,數據以B+樹的方式組織數據,導致單行數據不能超過8k,從而影響了表中大字段數據類型varchar,text,blob個數限制,在16k頁塊大小下,最好不要超過10個,在表設計中需要注意這個限制。
在innodb plugin的版本中,mysql引入了新的文件格式:barracuda,梭魚;改文件格式中擁有兩種新的行記錄:compressed,dynamic,這兩鍾格式對於BLOB數據完全采用行溢出方式,在數據頁中只占用20字節用於指向溢出頁。



Antelope是innodb-base的文件格式, Barracude是innodb-plugin后引入的文件格式,同時Barracude也支持Antelope文件格式。兩者區別在於:
文件格式
-
Antelope(Innodb-base)
支持行格式
ROW_FORMAT=COMPACT
ROW_FORMAT=REDUNDANT
特性
Compact和redumdant的區別在就是在於首部的存存內容區別。
compact的存儲格式為首部為一個非NULL的變長字段長度列表,redundant的存儲格式為首部是一個字段長度偏移列表(每個字段占用的字節長度及其相應的位移)。在Antelope中對於變長字段,低於768字節的,不會進行overflow page存儲,某些情況下會減少結果集IO. -
Barracuda(innodb-plugin)
支持行格式
ROW_FORMAT=DYNAMIC
ROW_FORMAT=COMPRESSED
特性
這兩者主要是功能上的區別功能上的。 另外在行里的變長字段和Antelope的區別是只存20個字節,其它的overflow page存儲。另外這兩都需要開啟innodb\_file\_per\_table=1(這個特性對一些優化還是很有用的)
innodb 一般對應 Compact ,MyISAM 一般對應靜態與動態
mysql中若一張表里面存在varchar、text以及其變形、blob以及其變形的字段的話,那么這個表其實也叫動態表,即該表的 row_format是dynamic,就是說每條記錄所占用的字節是動態的。其優點節省空間,缺點增加讀取的時間開銷。反之,這張表叫靜態表,該表 row_format為fixed,即每條記錄占用字節一樣。優點讀取快,缺點浪費部分空間,所以,做搜索查詢量大的表一般都以空間來換取時間,設計成靜態表。
修改行格式
ALTER TABLE table_name ROW_FORMAT = DEFAULT
修改過程導致:
fixed--->dynamic: 這會導致CHAR變成VARCHAR
dynamic--->fixed: 這會導致VARCHAR變成CHAR
備注:
這里有一點需要注意,如果要使用壓縮,一定需要先使用innodb_file_format =Barracuda格式,不然沒作用。
