MySQL 字符串类型

MySQL 中的字符串大体分为三类,这里不讨论第三类:

  • 长度以字符为单位的(character string 或 nonbinary string):CHARVARCHAR、TEXT(共四种:TINYTEXTTEXTMEDIUMTEXTLONGTEXT
  • 长度以字节为单位(binary string):BINARYVARBINARY、BLOB(共四种:TINYBLOBBLOBMEDIUMBLOBLONGBLOB
  • 其他:ENUMSET

下表为各种类型的最大长度:

单位 255(28 - 1) 65535(216 - 1) 255(28 - 1) 65535(216 - 1) 16,777,215(224 - 1) 4,294,967,295(232 - 1)
字符 CHAR VARCHAR TINYTEXT TEXT MEDIUMBLOB LONGBLOB
字节 BINARY VARBINARY TINYBLOB BLOB MEDIUMTEXT LONGTEXT

基本语法

字符类型(character string)(CHARVARCHARTEXTENUMSET) 和任何同义词可以指定列的字符集(character set)和排序规则(collation);但字节类型(binary string)不可以(字符集和排序规则是固定的 binary ):

  • CHARACTER SET 指定字符集, COLLATE 属性指定排序规则。CHARSETCHARACTER SET 的同义词。例如:

    CREATE TABLE t
    (
        c1 VARCHAR(20) CHARACTER SET utf8,
        c2 TEXT CHARACTER SET latin1 COLLATE latin1_general_cs
    );
    

    定义了一个名为 c1 的列,该列的字符集为 utf8,且使用该字符集的默认排序规则,以及一个名为 c2 的列,该列的字符集为 latin1 ,且排序规则是区分大小写 ( _cs) 的。

  • 为 character string 类型指定 CHARACTER SET binary 会导致将列创建为相应的 binary string 数据类型: CHAR 变成 BINARYVARCHAR 变成 VARBINARYTEXT 变成 BLOB。对于 ENUMSET 不会发生转换。例如:

    CREATE TABLE t
    (
      c1 VARCHAR(10) CHARACTER SET binary,
      c2 TEXT CHARACTER SET binary,
      c3 ENUM('a','b','c') CHARACTER SET binary
    );
    

    以上表定义的结果为:

    CREATE TABLE t
    (
      c1 VARBINARY(10),
      c2 BLOB,
      c3 ENUM('a','b','c') CHARACTER SET binary
    );
    
  • BINARY 属性是一个非标准的 MySQL 扩展,它是指定列字符集的二进制排序规则(_bin)的简写。例如:

    CREATE TABLE t
    (
      c1 VARCHAR(10) CHARACTER SET latin1 BINARY,
      c2 TEXT BINARY
    ) CHARACTER SET utf8mb4;
    

    以上表定义的结果为:

    CREATE TABLE t (
      c1 VARCHAR(10) CHARACTER SET latin1 COLLATE latin1_bin,
      c2 TEXT CHARACTER SET utf8mb4 COLLATE utf8mb4_bin
    ) CHARACTER SET utf8mb4;
    
  • ASCII 属性是 CHARACTER SET latin1 的简写。

  • UNICODE 属性是 CHARACTER SET ucs2 的简写。

不同于字符类型,字节类型(binary string)的字符集和排序规则是固定的,即 binary character set 和 collation,比较和排序是基于字节的,而字符类型是基于各种字符集排序规则的词汇表顺序的。

以下是各种类型的基本声明方式,[ ] 代表是可选项。

  • CHAR[(M)] [CHARACTER SET charset_name] [COLLATE collation_name]

    M 表示以字符为单位的列长度,范围是 0 到 255。如果省略 M,则长度为 1。

    MySQL 允许创建类型为 CHAR(0) 的列。当必须兼容依赖于列存在但不实际使用其值的旧应用程序时,这是非常有用的。CHAR(0) 也非常好,当你需要一个只能接受两个值的列时,CHAR(0) 也是个很好的选择:定义为 CHAR(0) 的列 NULL仅占用一位并且只能接受值 NULL''(空字符串)。

  • VARCHAR[(M)] [CHARACTER SET charset_name] [COLLATE collation_name]

  • BINARY[(M)]

    M 表示以字节为单位的列长度。如果省略,则默认为 1。

  • VARBINARY(M)

    M 表示以字节为单位的最大列长度。

  • TINYBLOB

  • TINYTEXT [CHARACTER SET charset_name] [COLLATE collation_name]

  • BLOB[(M)]

    可以为此类型提供可选长度 M。如果这样做,MySQL会将列创建为足够大的最小 BLOB 类型,以容纳 M 字节

  • TEXT[(M)] [CHARACTER SET charset_name] [COLLATE collation_name]

    可以为此类型提供可选长度 M。如果这样做,MySQL会将列创建为足够大的最小 TEXT 类型,以容纳 M 字符

  • MEDIUMBLOB

  • MEDIUMTEXT [CHARACTER SET charset_name] [COLLATE collation_name]

  • LONGBLOB

  • LONGTEXT [CHARACTER SET charset_name] [COLLATE collation_name]

  • ENUM('value1','value2',...) [CHARACTER SET charset_name] [COLLATE collation_name]

  • SET('value1','value2',...) [CHARACTER SET charset_name] [COLLATE collation_name]

binary string 的 binary collation 与 character string 的 _bin collation 的区别

二进制字符串(如 BINARYVARBINARYBLOB 数据类型)有一个名为 binary 的字符集和排序规则。二进制字符串是字节序列,这些字节的数值决定了比较和排序的顺序。见 Section 10.10.8, “The Binary Character Set”。

非二进制字符串(如 CHARVARCHARTEXT 数据类型)有一个字符集和 binary 以外的排序规则。给定的非二进制字符集可以有多个排序规则,每个排序规则为字符集中的字符定义特定的比较和排序顺序。其中之一是二进制排序规则,排序规则名称中带有 _bin 后缀。例如,latin1big5 的二进制排序规则分别为 latin1_binbig5_binutf8mb4 是一个例外,它有两个二进制排序规则,utf8mb4_binutf8mb4_0900_bin;请参见第 10.10.1 节 “Unicode 字符集”。

binary 排序规则和 _bin 排序规则在以下几个方面有所不同:

比较和排序的单位

二进制字符串是字节序列。对于 binary 排序规则,比较和排序基于数字字节值。非二进制字符串是字符序列,可能是多字节的。非二进制字符串的排序规则定义了用于比较和排序的字符值的顺序。对于_bin 排序规则,此排序基于数字字符代码值,这类似于二进制字符串的排序,但字符代码值可能是多字节的。

字符集转换

非二进制字符串具有字符集,并且在许多情况下会自动转换为另一个字符集,即使该字符串具有_bin排序规则:

  • 将列值分配给具有不同字符集的另一列时:

    UPDATE t1 SET utf8mb4_bin_column=latin1_column;
    INSERT INTO t1 (latin1_column) SELECT utf8mb4_bin_column FROM t2;
    
  • INSERTUPDATE 使用字符串文字分配列值时:

    SET NAMES latin1;
    INSERT INTO t1 (utf8mb4_bin_column) VALUES ('string-in-latin1');
    
  • 将结果从服务器发送到客户端时:

    SET NAMES latin1;
    SELECT utf8mb4_bin_column FROM t2;
    

对于二进制字符串列,不发生转换。对于类似于上述情况的情况,将按字节复制字符串值。

大小写转换

非二进制字符集的排序规则提供有关字符字母大小写的信息,因此非二进制字符串可以进行大小写转换,即使 _bin 排序规则忽略字母大小写:

mysql> SET NAMES utf8mb4 COLLATE utf8mb4_bin;
mysql> SELECT LOWER('aA'), UPPER('zZ');
+-------------+-------------+
| LOWER('aA') | UPPER('zZ') |
+-------------+-------------+
| aa          | ZZ          |
+-------------+-------------+

字母大小写的概念不适用于二进制字符串中的字节。要执行大小写转换,必须先转换为非二进制字符串(使用与存储在字符串中的数据相适应的字符集),再进行大小写转换:

mysql> SET NAMES binary;
mysql> SELECT LOWER('aA'), LOWER(CONVERT('aA' USING utf8mb4));
+-------------+------------------------------------+
| LOWER('aA') | LOWER(CONVERT('aA' USING utf8mb4)) |
+-------------+------------------------------------+
| aA          | aa                                 |
+-------------+------------------------------------+
比较时对尾部空格的处理

MySQL 排序规则有一个 pad 属性,其值为:PAD SPACENO PAD

  • 大多数 MySQL 排序规则的 pad 属性为 PAD SPACE
  • 基于 UCA 9.0.0 及更高版本的 Unicode 排序规则具有的 NO PAD 的 pad 属性;请参见第 10.10.1 节 “Unicode 字符集”。

对于非二进制字符串(CHARVARCHARTEXT),字符串排序规则 pad 属性确定字符串尾随空格比较的处理:

  • 对于 PAD SPACE 排序规则,尾随空格在比较中是不重要的;比较字符串时不考虑末尾的空格。
  • NO PAD 排序规则在比较中将尾随空格视为重要字符,就像其他字符一样。

可以使用两个 utf8mb4 二进制排序来演示不同的行为,其中一个是 PAD SPACE,另一个是 NO PAD。该示例还展示了如何使用 INFORMATION_SCHEMA COLLATIONS 表来确定排序规则的 pad 属性。

mysql> SELECT COLLATION_NAME, PAD_ATTRIBUTE
       FROM INFORMATION_SCHEMA.COLLATIONS
       WHERE COLLATION_NAME LIKE 'utf8mb4%bin';
+------------------+---------------+
| COLLATION_NAME   | PAD_ATTRIBUTE |
+------------------+---------------+
| utf8mb4_bin      | PAD SPACE     |
| utf8mb4_0900_bin | NO PAD        |
+------------------+---------------+
mysql> SET NAMES utf8mb4 COLLATE utf8mb4_bin;
mysql> SELECT 'a ' = 'a';
+------------+
| 'a ' = 'a' |
+------------+
|          1 |
+------------+
mysql> SET NAMES utf8mb4 COLLATE utf8mb4_0900_bin;
mysql> SELECT 'a ' = 'a';
+------------+
| 'a ' = 'a' |
+------------+
|          0 |
+------------+

在这个上下文中,“Comparison”不包括 LIKE 模式匹配操作符,对于它,不管排序顺序如何,后面的空格都是重要的。

对于二进制字符串(BINARYVARBINARYBLOB),所有字节在比较中都很重要,包括尾部的空格:

mysql> SET NAMES binary;
mysql> SELECT 'a ' = 'a';
+------------+
| 'a ' = 'a' |
+------------+
|          0 |
+------------+
插入和检索的尾随空格处理

CHAR(N) 列存储长度为 N 个字符的非二进制字符串。对于插入,小于 N 个字符的值将用空格填充。对于检索,尾部空格将被删除。

BINARY(N) 列存储长度为 N 个字节的二进制字符串。对于插入,小于 N 个字节的值将用 0x00 字节填充。对于检索,不会删除任何内容;总是返回一个声明长度的值。

mysql> CREATE TABLE t1 (
         a CHAR(10) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin,
         b BINARY(10)
       );
mysql> INSERT INTO t1 VALUES ('x','x');
mysql> INSERT INTO t1 VALUES ('x ','x ');
mysql> SELECT a, b, HEX(a), HEX(b) FROM t1;
+------+------------------------+--------+----------------------+
| a    | b                      | HEX(a) | HEX(b)               |
+------+------------------------+--------+----------------------+
| x    | 0x78000000000000000000 | 78     | 78000000000000000000 |
| x    | 0x78200000000000000000 | 78     | 78200000000000000000 |
+------+------------------------+--------+----------------------+

如果您计划使用 BINARY 存储二进制数据,并且您要求检索的值与存储的值完全相同,则应仔细考虑前面的填充和删除的特性 。以下示例说明了 BINARY0x00 填充如何影响列值比较:

mysql> CREATE TABLE t (c BINARY(3));
Query OK, 0 rows affected (0.01 sec)

mysql> INSERT INTO t SET c = 'a';
Query OK, 1 row affected (0.01 sec)

mysql> SELECT HEX(c), c = 'a', c = 'a\0\0' from t;
+--------+---------+-------------+
| HEX(c) | c = 'a' | c = 'a\0\0' |
+--------+---------+-------------+
| 610000 |       0 |           1 |
+--------+---------+-------------+
1 row in set (0.09 sec)

如果检索到的值必须与为未填充前存储的值相同,则最好使用 VARBINARYBLOB

PAD SPACE 行为的缺点

character string 对所有排序规则都具有 PAD SPACE 行为,也就是说比较时会自动在尾部填充空格。这会影响唯一索引的使用:

mysql> CREATE TABLE t (c VARCHAR(3), UNIQUE INDEX uk_c(c));
Query OK, 0 rows affected (0.03 sec)

mysql> INSERT INTO t VALUE('a');
Query OK, 1 row affected (0.01 sec)

mysql> INSERT INTO t VALUE('a ');
1062 - Duplicate entry 'a ' for key 'uk_c'

定长类型与非定长类型

定长类型(只有 CHARBINARY)占用的存储空间是固定的,即声明时指定的长度(单位可能是字节也可能是字符,取决于数据类型),如上述,若长度不足会进行尾部填充。

非定长类型的存储空间 = 数据实际占用的空间 + 额外的记录长度(单位都是字节)的空间。VARCHAR[M] 当 M <= 255 时需要一个额外字节,M > 255 时需要两个。TEXT(共四种:TINYTEXT、TEXT、MEDIUMBLOB、LONGBLOB)、BLOB(共四种:TINYBLOB、BLOB、MEDIUMTEXT、LONGTEXT)需要的额外空间都是固定的,分别为 1、2、3、4 个字节。

定长类型的坏处是可能会浪费空间。而非定长类型也不一定能节省空间,因为额外的长度字节是字符串级别的,也就是说每个单元格都需要一个额外的长度字节,数据量很大的话,需要的额外空间也是和很可观的。

定长类型存储时尾部填充的特性会影响唯一索引的使用(类似 PAD SPACE 的缺点),比如有列 c1 CHAR(3)c1 列有唯一索引 uk_c1,且表中已经有数据 'a' 了,再试图插入 'a ' 会发生重复键错误(Duplicate entry ‘a’ for key ‘uk_c1’)。

非定长类型存储时不会填充,被检索时也不会删除尾部填充值。

==CHAR 被检索时会删除尾部的空格,删除是无差别的,即使空格是程序提供的也会被删除。==这常常会导致困惑。如果数据的尾部可能存在空格,又想保证检索时与插入时的结果相同(比如,插入 'a ',查询出来的必须还是 'a ',不能是 ‘a’),则应该使用 VARCHAR,而不是 CHAR

示例:由于 CHAR 被检索时会删除尾部的所有空格,所以 列 c 的结果始终是 '(ab)' ;而 VARCHAR 没有填充与删除填充的特性,所有列 v 的结果始终都是符合正常思路的。

mysql> CREATE TABLE vc (v VARCHAR(4), c CHAR(4));
Query OK, 0 rows affected (0.01 sec)

mysql> INSERT INTO vc VALUES ('ab ', 'ab '), ('ab  ', 'ab  ');
Query OK, 1 row affected (0.00 sec)

mysql> SELECT CONCAT('(', v, ')'), CONCAT('(', c, ')') FROM vc;
+---------------------+---------------------+
| CONCAT('(', v, ')') | CONCAT('(', c, ')') |
+---------------------+---------------------+
| (ab )               | (ab)                |
+---------------------+---------------------+
| (ab  )              | (ab)                |
+---------------------+---------------------+
1 row in set (0.06 sec)

CHAR 的缺点是查询出的值可能丢失了尾部的空格。但是比较时不会有问题,因为字符类型的比较都是 PAD SPACE 的,尾部的空格在比较中是无关紧要的。示例中插入两条记录 ‘a’、'a ',查询时尾部的空格丢失了,结果都是 ‘a’。但是这不影响比较,c = 'a', c = 'a ' 的结果都是 TRUE

mysql> CREATE TABLE t (c CHAR(3));
Query OK, 0 rows affected (0.01 sec)

mysql> INSERT INTO t values('a'), ('a ');
Query OK, 2 rows affected (0.01 sec)
Records: 2  Duplicates: 0  Warnings: 0

mysql> SELECT CONCAT('(', c, ')'), c = 'a', c = 'a ' FROM t;
+---------------------+---------+----------+
| CONCAT('(', c, ')') | c = 'a' | c = 'a ' |
+---------------------+---------+----------+
| (a)                 |       1 |        1 |
| (a)                 |       1 |        1 |
+---------------------+---------+----------+
2 rows in set (0.02 sec)

字节类型的比较不是 PAD SPACE,所有字节在比较中都是至关重要的。且 BINARY 存储时填充 0x00,但被检索时不会删除尾部的 0x00,这有时会导致意想不到的比较失败。

如果检索到的值必须与为未填充前存储的值相同,则最好使用 VARBINARYBLOB

示例:由于列是 BINARY(3),那么 'a''a\0' 插入后都变成了 'a\0\0',又因为所有字节在比较中都是至关重要的,所以 c = 'a', c = 'a\0' 都是 FALSE,只有 c = 'a\0\0'TRUE

mysql> CREATE TABLE t (c BINARY(3));
Query OK, 0 rows affected (0.01 sec)

mysql> INSERT INTO t values('a', 'a\0');
Query OK, 1 row affected (0.01 sec)

mysql> SELECT HEX(c), c = 'a', c = 'a\0', c = 'a\0\0' from t;
+--------+---------+-----------+-------------+
| HEX(c) | c = 'a' | c = 'a\0' | c = 'a\0\0' |
+--------+---------+-----------+-------------+
| 610000 |       0 |         0 |           1 |
| 610000 |       0 |         0 |           1 |
+--------+---------+-----------+-------------+
2 rows in set (0.01 sec)

BLOB 与 TEXT 类型

在大多数方面,可以将 BLOB 列视为可以任意大的 VARBINARY 列。同样,可以将 TEXT 列视为 VARCHAR 列。 BLOBTEXT不同于 VARBINARYVARCHAR 的地方:

  • 对于BLOBTEXT列的索引,必须指定索引前缀长度。对于 CHARVARCHAR,前缀长度是可选的。
  • BLOBTEXT 列不能有 DEFAULT 值。

LONGLONG VARCHAR 会映射为 MEDIUMTEXT 类型,这是一个兼容性功能。

MySQL Connector/ODBC 将BLOB值定义为 LONGVARBINARY,将TEXT 值定义为LONGVARCHAR

因为BLOBTEXT 值可能非常长,所以在使用它们时可能会遇到一些限制:

  • 排序时只使用列的前 max_sort_length 个字节,默认值为 1024。可以通过在服务器启动或运行时增加 max_sort_length 的值来使排序或分组使用更多的字节数 。任何客户端都可以更改其会话 max_sort_length 变量的值:

    mysql> SET max_sort_length = 2000;
    mysql> SELECT id, comment FROM t
        -> ORDER BY comment;
    
  • 需要使用临时表处理的查询,若结果中包含 BLOBTEXT 列会导致服务器使用磁盘而不是内存,因为 MEMORY存储引擎不支持这些数据类型。使用磁盘会导致性能损失,因此仅在真正需要时才在查询结果中包含 BLOBTEXT列。例如,避免使用 SELECT *

  • BLOBTEXT对象的最大大小由其类型决定,但是实际上可以在客户端和服务器之间传输的最大值是由可用内存的数量和通信缓冲区的大小决定的。可以通过更改 max_allowed_packet 变量的值来更改消息缓冲区大小 ,但必须同时对服务器和客户端都设置。

列的最大长度限制、行大小限制与列的数量限制

文章一开始给出的关于数据类型最大长度的表格只是最理想的最大长度。实际上列的最大长度受限于行大小与列数:

列数限制

MySQL 对每个表有 4096 列的硬限制,但对于给定表,有效最大值可能会更少。确切的列限制取决于几个因素:

  • 表的最大行大小限制了列的数量(可能还有列的大小),因为所有列的总长度不能超过此大小。
  • 在给定了最大行大小的情况下,单个列的存储要求限制了列数。某些数据类型的存储要求取决于存储引擎、存储格式和字符集等因素。请参见 Section 11.7, “Data Type Storage Requirements”。
  • 存储引擎可能会施加额外的限制来限制表的列数。例如,InnoDB 限制每个表最多有 1017 列的。请参阅 Section 14.23, “InnoDB Limits”。有关其他存储引擎的信息,请参阅 Chapter 15, Alternative Storage Engines
  • 每个表都有一个包含表定义的 .frm 文件。该定义以可能影响表中允许的列数的方式影响此文件的内容。请参阅 Limits Imposed by .frm File Structure。
行大小限制

给定表的最大行大小由几个因素决定:

  • MySQL 表的内部表示的最大行大小限制是 65,535 字节,即使存储引擎能够支持更大的行。 BLOBTEXT 列仅对行大小贡献 9 到 12 个字节,因为它们的内容与行的其余部分分开存储。

  • InnoDB 表的最大行大小略小于半个页(页指的是 innodb_page_size 设置,比如 4KB、8KB、16KB和32KB)。例如,对于默认的 16KB InnoDB页大小,最大行大小略小于 8KB 。对于 64KB 页面,最大行大小略小于 16KB。请参阅 Section 14.23, “InnoDB Limits”。

    如果包含可变长度列的 InnoDB 行超过了最大行大小,InnoDB 就会选择变长列进行页外存储,直到该行符合InnoDB 行大小限制。对于页外存储的可变长度列,本地存储的数据量因行格式而异。有关更多信息,请参阅 Section 14.11, “InnoDB Row Formats”。

  • 不同的存储格式使用不同数量的 page header 和 trailer 数据,这会影响行可用的存储量。

    • 有关InnoDB行格式的信息,请参阅 Section 14.11, “InnoDB Row Formats”。
    • 有关MyISAM 存储格式的信息,请参阅 Section 15.2.3, “MyISAM Table Storage Formats”。
行大小限制示例
  • 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 字节的行大小限制,并允许操作成功,因为 BLOBTEXT 列只对行大小贡献 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 列需要两个字节来存储值的长度,因此每个值最多会占用 767 个字节。

    创建表 t1 的语句执行成功,因为列需要 32,765 + 2 + 32,766 + 2 = 65,535 个字节,这在 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)
    

    create table 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 列多占一 bit,四舍五入到最接近的字节。

    创建表的语句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 列存储的信息,请参阅 Section 14.11, “InnoDB Row Formats”.。

  • 对于 4KB、8KB、16KB 和 32KB 的 innodb_page_size 设置,InnoDB 将限制行大小为略小于数据库页的一半, 对于 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=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.
    

你可能感兴趣的:(MySQL,mysql,字符串)