今天拿到一個(gè)建語句時(shí),大概二百多個(gè)字段,然后大部分類型是 string 的,要求建 MySQL 的表。首先將 string 替換為 varchar(xx),然后執(zhí)行了一下語句,報(bào)錯(cuò)如下所示:
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.
報(bào)錯(cuò)原因:
MySQL 建表時(shí)有一個(gè)單行最大限制長度限定:一張表中所有字段設(shè)置的字節(jié)數(shù)總和不大于 65535 字節(jié)。
注意點(diǎn)一:單個(gè)字段大小超過 65535 轉(zhuǎn)換為 TEXT。
注意點(diǎn)二:其余字段總和不超過 65535 字節(jié)(不包括 BLOB/TEXT)。
注意點(diǎn)三:數(shù)據(jù)庫使用 UTF-8 編碼,一個(gè)字符 = 三個(gè)字節(jié)大?。ㄊ褂镁幋a不同,字節(jié)數(shù)大小略有不同)。
報(bào)錯(cuò)舉例:數(shù)據(jù)庫存在 10 個(gè) varchar 字段,每個(gè)大小為 3000 則數(shù)據(jù)庫單行目前計(jì)算長度為 3000 * 10 * 3 = 90000 > 65535 ,則建表時(shí)就會報(bào)錯(cuò)。
解決辦法: 將數(shù)據(jù)庫表大字段類型設(shè)置為 TEXT,或者將部分可以減小長度的長度調(diào)小至總和小于 65535。
調(diào)整完之后,執(zhí)行建表語句,又報(bào)如下錯(cuò)誤:
1. Row size too large (> 8126). Changing some columns to TEXT or BLOB or using ROW_FORMAT=DYNAMIC or ROW_FORMAT=COMPRESSED may help. In current row format, BLOB prefix of 768 bytes is stored inline.
(低版本報(bào)錯(cuò))
2. Row size too large (> 8126). Changing some columns to TEXT or BLOB may help. In current row format, BLOB prefix of 0 bytes is stored inline.
(新版本報(bào)錯(cuò))
上面兩個(gè)錯(cuò)誤信息,前者基本出現(xiàn)在 ROW_FORMAT <> DYNAMIC
或者較早版本的情況,在其中 BLOB 需要存儲 768 字節(jié)在行內(nèi)部。對整個(gè)行 size 貢獻(xiàn)較大。
后者基本對于較新的版本,因?yàn)槟J(rèn)的 ROW_FORMAT = DYNAMIC
,在其中,一個(gè) TEXT 或者 BLOB 字段對行 size 的貢獻(xiàn)在 9-12 個(gè)字節(jié)之間。
對于第一種情況,可以設(shè)置 innodb_file_per_table = 1
,innodb_default_row_format = dynamic
,又因?yàn)?dynamic 要求 innodb_file_format
必須為 Barracuda
,所以一般還要加上 innodb_file_format = Barracuda
設(shè)置。innodb_default_row_format = dynamic
可以在創(chuàng)建表的時(shí)候動態(tài)指定。當(dāng)然也可以按照提示那樣的,設(shè)置 ROW_FORMAT =COMPRESSED
,這個(gè)對于只讀場景用處比較大,如果用于讀寫負(fù)載,那比較不好。
在數(shù)據(jù)庫執(zhí)行如下語句:
SHOW GLOBAL VARIABLES LIKE '%innodb_file%';
+--------------------------+-----------+
| Variable_name | Value |
+--------------------------+-----------+
| innodb_file_format | Barracuda |
| innodb_file_format_check | ON |
| innodb_file_format_max | Barracuda |
| innodb_file_per_table | ON |
+--------------------------+-----------+
確保 innodb_file_format
使用的是 Barracuda
,innodb_file_per_table
使用的是 ON
,如果不是執(zhí)行以下語句(不用重啟 MySQL):
SET GLOBAL innodb_file_format = barracuda;
SET GLOBAL innodb_file_per_table = ON;
或者,在配置文件中添加使用獨(dú)立表空間的配置:innodb_file_per_table=1
修改配置文件 my.cnf(需要重啟 MySQL):
innodb_file_per_table = ON;
innodb_file_format = barracuda;
或者,建表語句設(shè)置 ROW_FORMAT =COMPRESSED
:
create table_name (
...
)
ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin ROW_FROMAT=COMPRESSED COMMENT='表注釋';
如果上面的方法仍然解決不了問題,那還有其它辦法:
1、關(guān)掉 innodb_strict_mode
,這個(gè)選項(xiàng)是在創(chuàng)建表的時(shí)候檢查行大小,如果確定實(shí)際存儲的字段沒有這么多,可以關(guān)掉。但是問題是如果確實(shí)有這么多內(nèi)容,插入的時(shí)候會報(bào)錯(cuò)。
查看:
SHOW VARIABLES LIKE '%innodb_strict_mode%';
+--------------------------+-----------+
| Variable_name | Value |
+--------------------------+-----------+
| innodb_strict_mode | ON |
+--------------------------+-----------+
修改:
SET SESSION innodb_strict_mode = OFF
或者
SET innodb_strict_mode = OFF
以上 OFF
也可以用 0
代替,ON
也可以用 1
代替 。
2、將 innodb_page_size
調(diào)整成 64K,這樣,64K 的 page 即使需要容納2行數(shù)據(jù)的話,每行也可以最大達(dá)到 32K(實(shí)際達(dá)不到,因?yàn)?header 和 footer 需要空間)。但是這個(gè)最好把現(xiàn)有的 MySQL 備份出來,然后按照新的 page size 重新初始化,再導(dǎo)入備份,保證整個(gè)庫都使用統(tǒng)一的 page size 大小,以免出現(xiàn)稀奇古怪的問題。
set global innodb_page_size = 65536
3、可以看到上面的提示 In current row format, BLOB prefix of 0 bytes is stored inline
,把較長的字段都轉(zhuǎn)成 TEXT 或者 BLOB 存儲。
以上步驟可以一個(gè)一個(gè)試,基本就可以解決自己的問題了。
詳細(xì)解釋:
ERROR1118 的報(bào)錯(cuò)信息分為兩種:
1. 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(定義到這個(gè)長度也會報(bào)錯(cuò),行本身維護(hù)也會占用字節(jié)),建議使用 TEXT 或 BLOBs 類型。
2. Row size too large (> 8126). Changing some columns to TEXT or BLOB may help. In current row format, BLOB prefix of 0 bytes is stored inline.
一條記錄太長,超過了 8126 字節(jié),建議部分列使用 TEXT 或 BLOB 類型。
看到這兩個(gè)報(bào)錯(cuò)信息,有些人可能就會有疑問,感覺描述的有些沖突,一個(gè)說一條記錄最大長度不超過 65535 字節(jié),一個(gè)說長度不能超過 8126 字節(jié)。那么到底哪個(gè)是正確的的呢?
先看下官方文檔的描述:
https://dev.mysql.com/doc/refman/5.7/en/column-count-limit.html#row-size-limits
【The MySQL maximum row size limit of 65,535 bytes is demonstrated in the following InnoDB and MyISAM examples. The limit is enforced regardless of storage engine, even though the storage engine may be capable of supporting larger rows.】
在 MySQL 數(shù)據(jù)庫中一條記錄的最大長度是 65535 字節(jié),在下面的 InnoDB 和 MyISAM 示例中做了演示。盡管存儲引擎可能能夠支持更大的行,但無論使用何種存儲引擎,都會強(qiáng)制執(zhí)行該限制。
【InnoDB restricts row size (for data stored locally within the database page) to slightly less than half a database page for 4KB, 8KB, 16KB, and 32KB innodb_page_size settings, and to slightly less than 16KB for 64KB pages.】
InnoDB 限制一條記錄的大小(對于本地存儲在數(shù)據(jù)庫頁面中的數(shù)據(jù)),對于 4KB、8KB、16KB 和 32KB 的 innodb_page_size
設(shè)置為略小于數(shù)據(jù)庫頁面的一半,對于 64KB 的頁面則略小于 16KB。
小結(jié):一條記錄最大長度 65535 字節(jié)是 MySQL 數(shù)據(jù)庫 Server 層面的限制
,默認(rèn)情況下,InnoDB 頁面大小是 16KB,所以 一條記錄在頁面中的存儲長度不能超過 8126 字節(jié)
,這是 InnoDB 存儲引擎的限制。
這里可能會有些疑問,平常創(chuàng)建 varchar(10000) 類型字段,已經(jīng)超過 8126 了,但也沒報(bào)這個(gè)錯(cuò)誤,這個(gè)和 InnoDB 的存儲一條記錄的格式有關(guān)系,官方文檔對存儲格式的說明:
https://dev.mysql.com/doc/refman/5.7/en/innodb-row-format.html#innodb-row-format-compact
【Fixed-length columns greater than or equal to 768 bytes are encoded as variable-length columns, which can be stored off-page】
當(dāng)列的長度超過 768 字節(jié)時(shí),多余的內(nèi)容會存儲到一個(gè)溢出頁上,compact/dynamic 格式在這方面是一樣的。
也就是說創(chuàng)建了 varhcar(10000) 類型字段,同時(shí)寫入到 10000 字節(jié)的數(shù)據(jù),其實(shí)只有 768 個(gè)字節(jié)存儲在數(shù)據(jù)頁面上,其余的字節(jié)存儲在溢出頁面上。
為什么Innodb存儲引擎,每個(gè)存儲頁面上,最少要有兩條記錄呢?
截圖來自于【MySQL運(yùn)維內(nèi)參】
這是假如每個(gè)頁面只能存儲一條記錄的情況下,表內(nèi)存儲了【1,2,3,4】4 條記錄 B+ 樹結(jié)構(gòu)圖,如果一個(gè)頁面的數(shù)據(jù)量不能存儲 2 條記錄,則這個(gè) B+ 樹就不能稱為 B+ 樹,因?yàn)樗鸩坏揭粋€(gè)索引的作用,其實(shí)就是一個(gè)雙向鏈表,但比雙向鏈表占用的空間大很多。
如果不能夠存儲 2 條記錄,那么這個(gè) B+ 樹是沒有意義的,形不成一個(gè)有效的索引。
總結(jié):
創(chuàng)建表和寫入數(shù)據(jù)時(shí)有兩個(gè)限制,一個(gè)是 Server 層面的限制,一條記錄最大長度不能超過 65535(真實(shí)創(chuàng)建的記錄長度到不了 65535,因?yàn)橛涗洷旧硪残枰恍┳止?jié)去維護(hù)),另一個(gè)是 InnoDB 層面的限制,一條記錄存儲在頁面中的長度不能夠超過 8126 字節(jié)。
行大小限制示例:
1、在 MySQL 數(shù)據(jù)庫中一條記錄的最大長度是 65535 字節(jié),在下面的 InnoDB 和 MyISAM 示例中做了演示。盡管存儲引擎可能能夠支持更大的行,但無論使用何種存儲引擎,都會強(qiáng)制執(zhí)行該限制。
創(chuàng)建一個(gè)表 t,記錄長度之合超過 65535。默認(rèn)字符集是 latin1,一個(gè)字符占一個(gè)字節(jié),如果用的 utf8,則一個(gè)字符占用 3 個(gè)字節(jié)。要在定義的 varchar 字段類型上乘以 3 才是占用字節(jié)數(shù)(不同字符集所占字節(jié)數(shù)可能不同)。
InnoDB 示例:
mysql> CREATE TABLE t (
a VARCHAR(10000), b VARCHAR(10000),
c VARCHAR(10000), d VARCHAR(10000), e VARCHAR(10000),
f VARCHAR(10000), g VARCHAR(6000)
) ENGINE=InnoDB CHARACTER SET latin1;
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
或者 MyISAM 示例:
mysql> CREATE TABLE t (
a VARCHAR(10000), b VARCHAR(10000),
c VARCHAR(10000), d VARCHAR(10000), e VARCHAR(10000),
f VARCHAR(10000), g VARCHAR(6000)
) ENGINE=MyISAM CHARACTER SET latin1;
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
在下面的 MyISAM 示例中,將列更改為 TEXT 避免了 65535 字節(jié)的行大小限制,所以就操作成功了,因?yàn)?BLOB 和 TEXT 列只貢獻(xiàn)了 9-12 個(gè)字節(jié)的行大?。?code>6 * 10000 + 9 ~ 6 * 10000 + 12
)。
mysql> CREATE TABLE t2 (
a VARCHAR(10000), b VARCHAR(10000),
c VARCHAR(10000), d VARCHAR(10000), e VARCHAR(10000),
f VARCHAR(10000), g TEXT(6000)
) ENGINE=MyISAM CHARACTER SET latin1;
Query OK, 0 rows affected (0.02 sec)
對于下面 InnoDB 表,操作成功,是因?yàn)閷⒘懈臑?TEXT 可避免 MySQL中 65535 字節(jié)的行大小限制,而 InnoDB 變長列的分頁存儲可避免 InnoDB 行大小限制(< 8126 的限制)。
看 t2 表,varchar 類型是 10000,記錄最長是 5 * 10000 = 50000
字節(jié),再加上TEXT 字段對行 size 貢獻(xiàn)的 9-12 個(gè)字節(jié),沒有達(dá)到 server 層面的限制。
對于可變長字段,數(shù)值超過 768 個(gè)字節(jié)的,字段的前 768 字節(jié)存儲在 InnoDB 頁面上,其余的數(shù)據(jù)存儲在溢出頁面上。t2 表一共 7 個(gè)字段,每個(gè)字段只有前邊的 768 字節(jié)存儲在 InnoDB 頁面上,7 * 768 = 5376
字節(jié),沒有達(dá)到 InnoDB 存儲引擎 8126 的限制,不會報(bào)錯(cuò),所以創(chuàng)建成功。
mysql> CREATE TABLE t2 (
a VARCHAR(10000), b VARCHAR(10000),
c VARCHAR(10000), d VARCHAR(10000), e VARCHAR(10000),
f VARCHAR(10000), g TEXT(6000)
) ENGINE=InnoDB CHARACTER SET latin1;
Query OK, 0 rows affected (0.02 sec)
可變長度列的存儲包括長度字節(jié)(值的長度),它被計(jì)入行大小。例如,VARCHAR(255)CHARACTER SET utf8mb3
列需要兩個(gè)字節(jié)來存儲值的長度,因此每個(gè)值最多占用 767 個(gè)字節(jié)。如下示例:
mysql> CREATE TABLE t3 (
c1 VARCHAR(32765) NOT NULL,
c2 VARCHAR(32766) NOT NULL
) ENGINE = InnoDB CHARACTER SET latin1;
Query OK, 0 rows affected (0.02 sec)
上面創(chuàng)建表 t3 的語句成功,因?yàn)榱行枰?32765 + 2 字節(jié)和 32766 + 2 字節(jié),這在 65535 字節(jié)的最大行大小范圍內(nèi)。
mysql> CREATE TABLE t3 (
c1 VARCHAR(65535) NOT NULL
) ENGINE = InnoDB CHARACTER SET latin1;
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
上面創(chuàng)建表 t3 的語句失敗,因?yàn)楸M管列長度在 65535 字節(jié)的最大長度內(nèi),但需要另外兩個(gè)字節(jié)來記錄長度,這會導(dǎo)致行大小超過 65535 個(gè)字節(jié)。
2、InnoDB 限制一條記錄的大小(對于本地存儲在數(shù)據(jù)庫頁面中的數(shù)據(jù)),對于 4KB、8KB、16KB 和 32KB 的 innodb_page_size
設(shè)置為略小于數(shù)據(jù)庫頁面的一半,對于 64KB 的頁面則略小于 16KB。
示例:
創(chuàng)建表 t4,使用 char(255) 定長字符串類型,char 類型無論寫入的內(nèi)容多少(當(dāng)然,一定要小于等于 255),在實(shí)際存儲時(shí)都會占用 255 個(gè)字節(jié)。一共33字段,每個(gè)字段定長 255 字節(jié),33 * 255 = 8415,每個(gè)記錄最大長度是 8145 字節(jié),是 Server 層的限制之內(nèi),所以沒報(bào) 65535 的錯(cuò)誤,但一條記錄在 InnoDB 頁面存儲時(shí)超過了 8126 限制,所以 InnoDB 存儲引擎報(bào)錯(cuò)了。如下所示:
mysql> CREATE TABLE t4 (
c1 CHAR(255),c2 CHAR(255),c3 CHAR(255),
c4 CHAR(255),c5 CHAR(255),c6 CHAR(255),
c7 CHAR(255),c8 CHAR(255),c9 CHAR(255),
c10 CHAR(255),c11 CHAR(255),c12 CHAR(255),
c13 CHAR(255),c14 CHAR(255),c15 CHAR(255),
c16 CHAR(255),c17 CHAR(255),c18 CHAR(255),
c19 CHAR(255),c20 CHAR(255),c21 CHAR(255),
c22 CHAR(255),c23 CHAR(255),c24 CHAR(255),
c25 CHAR(255),c26 CHAR(255),c27 CHAR(255),
c28 CHAR(255),c29 CHAR(255),c30 CHAR(255),
c31 CHAR(255),c32 CHAR(255),c33 CHAR(255)
) ENGINE=InnoDB ROW_FORMAT=COMPACT DEFAULT CHARSET latin1;
ERROR 1118 (42000): Row size too large (> 8126). Changing some columns to TEXT or BLOB or using
ROW_FORMAT=DYNAMIC or ROW_FORMAT=COMPRESSED may help. In current row format, BLOB prefix of 768
bytes is stored inline.
創(chuàng)建表 t4 的語句失敗,因?yàn)槎x的列超過了 16KB InnoDB 頁面的行大小限制。
修改 t4 表為 varhcar(255),可變長字段試下,varchar 字段類型在實(shí)際存儲到頁面的時(shí)候,并不以定長存儲,而是寫入多少字節(jié),存儲多少字節(jié)。如下所示,可以看到,這樣創(chuàng)建表是沒有問題,如果寫入字節(jié)數(shù)小于 8126 字節(jié)也沒有問題,但是如果寫入字節(jié)數(shù)超過 8126 了,由于 InnoDB 存儲引擎的限制,還是會報(bào)錯(cuò)的。
mysql> CREATE TABLE t4 (
c1 VARCHAR(255),c2 VARCHAR(255),c3 VARCHAR(255),
c4 VARCHAR(255),c5 VARCHAR(255),c6 VARCHAR(255),
c7 VARCHAR(255),c8 VARCHAR(255),c9 VARCHAR(255),
c10 VARCHAR(255),c11 VARCHAR(255),c12 VARCHAR(255),
c13 VARCHAR(255),c14 VARCHAR(255),c15 VARCHAR(255),
c16 VARCHAR(255),c17 VARCHAR(255),c18 VARCHAR(255),
c19 VARCHAR(255),c20 VARCHAR(255),c21 VARCHAR(255),
c22 VARCHAR(255),c23 VARCHAR(255),c24 VARCHAR(255),
c25 VARCHAR(255),c26 VARCHAR(255),c27 VARCHAR(255),
c28 VARCHAR(255),c29 VARCHAR(255),c30 VARCHAR(255),
c31 VARCHAR(255),c32 VARCHAR(255),c33 VARCHAR(255)
) ENGINE=InnoDB ROW_FORMAT=COMPACT DEFAULT CHARSET latin1;
Query OK, 0 rows affected (0.01 sec)
寫入數(shù)據(jù)長度小于 8126 的場景,240 * 33 = 7920,可以成功。如下所示:
mysql> insert into t4 (
c1,c2,c3,c4,c5,c6,c7,c8,
c9,c10,c11,c12,c13,c14,c15,c16,
c17,c18,c19,c20,c21,c22,c23,c24,
c25,c26,c27,c28,c29,c30,c31,c32,c33
) values(
repeat('a',240),repeat('a',240),repeat('a',240),repeat('a',240),repeat('a',240),repeat('a',240),repeat('a',240),repeat('a',240),
repeat('a',240),repeat('a',240),repeat('a',240),repeat('a',240),repeat('a',240),repeat('a',240),repeat('a',240),repeat('a',240),
repeat('a',240),repeat('a',240),repeat('a',240),repeat('a',240),repeat('a',240),repeat('a',240),repeat('a',240),repeat('a',240),
repeat('a',240),repeat('a',240),repeat('a',240),repeat('a',240),repeat('a',240),repeat('a',240),repeat('a',240),repeat('a',240),repeat('a',240)
)
Query OK, 1 row affected (0.01 sec)
寫入數(shù)據(jù)長度大于 8126 的場景,255 * 33 = 8415,直接報(bào)錯(cuò)。如下所示:文章來源:http://www.zghlxwxcb.cn/news/detail-407406.html
mysql> insert into t4 (
c1,c2,c3,c4,c5,c6,c7,c8,
c9,c10,c11,c12,c13,c14,c15,c16,
c17,c18,c19,c20,c21,c22,c23,c24,
c25,c26,c27,c28,c29,c30,c31,c32,c33
) values(
repeat('a',255),repeat('a',255),repeat('a',255),repeat('a',255),repeat('a',255),repeat('a',255),repeat('a',255),repeat('a',255),
repeat('a',255),repeat('a',255),repeat('a',255),repeat('a',255),repeat('a',255),repeat('a',255),repeat('a',255),repeat('a',255),
repeat('a',255),repeat('a',255),repeat('a',255),repeat('a',255),repeat('a',255),repeat('a',255),repeat('a',255),repeat('a',255),
repeat('a',255),repeat('a',255),repeat('a',255),repeat('a',255),repeat('a',255),repeat('a',255),repeat('a',255),repeat('a',255),repeat('a',255)
)
ERROR 1118 (42000): Row size too large (> 8126). Changing some columns to TEXT or BLOB or using
ROW_FORMAT=DYNAMIC or ROW_FORMAT=COMPRESSED may help. In current row format, BLOB prefix of 768
bytes is stored inline.
mysql>
參考文章:
https://blog.csdn.net/w1346561235/article/details/110636226
https://www.cnblogs.com/nanxiang/p/13056093.html文章來源地址http://www.zghlxwxcb.cn/news/detail-407406.html
到了這里,關(guān)于MySQL報(bào)錯(cuò):ERROR 1118 (42000): Row size too large. 或者 Row size too large (> 8126).的文章就介紹完了。如果您還想了解更多內(nèi)容,請?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!