参考资料
https://dev.mysql.com/doc/refman/8.0/en/column-count-limit.html
1. InnoDB 单行最大限制
InooDB 单行最大不能超过页大小的一半,比如默认 innodb_page_size=16K,则单行不能超过 8k(要减去一些额外信息占用的大小):
CREATE TABLE t5 (
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=DYNAMIC DEFAULT CHARSET latin1;
ERROR 1118 (42000): 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.
1.1 行溢出
如果包含可变长度类型的字段的行超过InnoDB 最大行大小,则 InnoDB 会选择吧可变长度字段存储到外部页(也叫溢出页),直到该行符合InnoDB 行大小限制:
- varchar、text、BLOB 类型的字段(变长的数据类型),在单行超出数据页一半大小时,会发生溢出:在记录真实数据的位置只记录部分字节,然后用一个指针记录其他数据存储的地址。
将上述示例 char 类型改为 varchar 类型,则可以突破单行不能超过 8k的限制:
CREATE TABLE t5 (
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=DYNAMIC DEFAULT CHARSET latin1;
Query OK, 0 rows affected (0.04 sec)
2. MySQL 层单行最大限制
MySQL层单行最大限制(不区分存储引擎)65535 字节:
mysql> create table t9(
-> c1 VARCHAR(65535)
-> ) ENGINE=InnoDB ROW_FORMAT=DYNAMIC DEFAULT CHARSET 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
##因为varchar类型超过 255 字符需要使用2个字节来存储真实的长度,1个字节存储NULL标记,所以不能超过65532字节
mysql> create table t9( c1 VARCHAR(65532) ) ENGINE=InnoDB ROW_FORMAT=DYNAMIC DEFAULT CHARSET latin1;
Query OK, 0 rows affected (0.02 sec)
2.1 为什么 TEXT、BLOB 类型可以超出 65535 最大长度?
BLOB、TEXT 列仅对行大小限制贡献 9 到 12 个字节,因为它们的内容与行的其余部分分开存储:
mysql> create table t9( c1 text(65536) ) ENGINE=InnoDB ROW_FORMAT=DYNAMIC DEFAULT CHARSET latin1;
Query OK, 0 rows affected (0.03 sec)