本节描述了表中的列数限制和单行大小限制。
MySQL 有一个硬性限制,每个表最多可以有 4096 列,但实际上的最大列数可能小于该限制。确切的列数限制取决于多个因素:
-
表的最大行大小限制了列数(可能还有列的大小)。见 行大小限制。
-
单个列的存储要求限制了在给定最大行大小内可以容纳的列数。某些数据类型的存储要求取决于存储引擎、存储格式和字符集。见 第 13.7 节,“数据类型存储要求”。
-
存储引擎可能会施加额外的限制,从而限制表的列数。例如,
InnoDB
每个表最多可以有 1017 列。见 第 17.21 节,“InnoDB 限制”。有关其他存储引擎的信息,请见 第 18 章,《替代存储引擎》。 -
功能键部分(见 第 15.1.15 节,“CREATE INDEX 语句”)被实现为隐藏的虚拟生成的存储列,因此每个表索引中的功能键部分都计入表的总列数限制。
给定表的最大行大小限制取决于多个因素:
-
MySQL 表的内部表示形式有一个最大行大小限制为 65,535 字节,即使存储引擎能够支持更大的行。
BLOB
和TEXT
列只占用 9 到 12 字节的行大小限制,因为它们的内容存储在行的其余部分之外。 -
InnoDB 表的最大行大小,对于在数据库页中存储的数据,略小于 4KB、8KB、16KB 和 32KB
innodb_page_size
设置的半页。例如,对于默认的 16KB InnoDB 页大小,最大行大小略小于 8KB。对于 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
列需要一个额外的位,四舍五入到最近的字节。创建表
t3
的语句失败,因为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
的语句失败,因为定义的列超过了 16KBInnoDB
页的行大小限制。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.