10.4.7 表列数和行大小限制
本节描述了表的列数限制和行大小限制。
MySQL 对表的列数有硬限制为4096,但实际最大值取决于给定的表。具体的列数限制因素多种:
-
表的最大行大小限制了列数(可能是大小)因为所有列的总长度不能超过这个大小。见行大小限制。
-
个别列的存储要求限制了在给定的最大行大小内可以容纳的列数。某些数据类型的存储要求取决于存储引擎、存储格式和字符集。见第13.7节,“数据类型存储要求”。
-
存储引擎可能会对表列数施加额外限制,例如
InnoDB
每个表的列数限制为1017。见第17.21节,“InnoDB限制”。关于其他存储引擎,见Alternative Storage Engines。 -
函数键部分(见第15.1.15节,“CREATE INDEX 语句”)以隐藏的虚拟生成存储列实现,因此每个表索引中的函数键部分都计入总列数限制。
给定表的最大行大小由以下因素确定:
-
MySQL 表的内部表示有一个最大行大小限制为65,535字节,即使存储引擎可以支持更大的行。
BLOB
和TEXT
列只会对行大小限制贡献9到12字节,因为它们的内容与表其他部分存储在一起。 -
InnoDB 表的最大行大小,适用于数据库页面中的数据,是4KB、8KB、16KB和32KB
innodb_page_size
设置的半页以下。例如,默认的16KB InnoDB 页大小,最大行大小是16KB以下。64KB 页时,最大行大小是16KB以下。见第17.21节,“InnoDB限制”。如果包含可变长度列的行超过 InnoDB 最大行大小,InnoDB 选择可变长度列进行外部离页存储直到行适应 InnoDB 行大小限制。可变长度列在离页存储中的数据量不同,取决于行格式。更多信息,请见第17.10节,“InnoDB 行格式”。
-
不同的存储格式使用不同的页头和尾数据,影响行的存储空间。
-
关于 InnoDB 行格式,请见第17.10节,“InnoDB 行格式”。
-
关于 MyISAM 存储格式,请见第18.2.3节,“MyISAM 表存储格式”。
-
-
MySQL 的最大行大小限制为 65,535 字节,以下是
InnoDB
和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=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
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
避免了 65,535 字节的行大小限制,并允许操作成功,因为BLOB
和TEXT
列只占用 9 到 12 字节。mysql> CREATE TABLE t (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
表来说,改变一个列为TEXT
避免了 MySQL 65,535 字节的行大小限制,而InnoDB
的变长列离页存储避免了InnoDB
行大小限制。mysql> CREATE TABLE t (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)
-
变长列的存储包括长度字节,这些字节被计入行大小。例如,一个
VARCHAR(255) CHARACTER SET utf8mb3
列需要 2 字节来存储值的长度,所以每个值最多占用 767 字节。创建表
t1
的语句成功,因为列要求 32,765 + 2 字节和 32,766 + 2 字节,落在最大行大小限制的 65,535 字节之内:mysql> CREATE TABLE t1 (c1 VARCHAR(32765) NOT NULL, c2 VARCHAR(32766) NOT NULL) ENGINE = InnoDB CHARACTER SET latin1; Query OK, 0 rows affected (0.02 sec)
创建表
t2
的语句失败,因为,虽然列的长度在 65,535 字节以内,但是需要额外两个字节来记录列的长度,从而导致行大小超过 65,535 字节:mysql> CREATE TABLE t2 (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
将列的长度减少到 65,533 字节或更小可以使语句成功。
mysql> CREATE TABLE t2 (c1 VARCHAR(65533) NOT NULL) ENGINE = InnoDB CHARACTER SET latin1; Query OK, 0 rows affected (0.01 sec)
-
MyISAM
表中,NULL
列需要额外的空间来记录其值是否为NULL
。每个NULL
列占用一个字节,向上取整。MyISAM
表创建语句失败,因为MyISAM
需要为NULL
列和变长列长度字节分配额外空间,从而导致行大小超过 65,535 字节:mysql> CREATE TABLE t3 (c1 VARCHAR(32765) NULL, c2 VARCHAR(32766) NULL) 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
InnoDB
NULL
列存储信息,请参阅第17.10节,“InnoDB 行格式”。 -
InnoDB
对行大小(在数据库页面中存储数据)进行限制,根据 4KB、8KB、16KB 和 32KBinnodb_page_size
设置的值为半页以下,对于 64KB 页则限制在 16KB 以下。创建表语句
t4
失败,因为定义的列超过了16KB InnoDB 页面的行大小限制。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=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.