1 理论说明
在官方文档里,提到MySQL的行记录的最大长度:65535 bytes.
The internal representation of a MySQL table has a maximum row size limit of 65,535 bytes.
https://dev.mysql.com/doc/refman/5.7/en/column-count-limit.html
这里的65535 是所有列共享的长度,即MySQL 表中所有列的长度加起来不能超过65535个字节。
在Mysql 5.0 之后,列的类型,比如varchar(20)指的是字符。而在不同的字符集中,字符和字节的关系也不一样,在utf8字符集中,一个汉字占3个字节,新的utf8mb4字符集中一个汉字占4个字节。所以如果列的字符串只保存英文,那么长度是一样的,但如果有中文,就会有出入。
因此在不同的字符集下,能够列定义的最大长度就会有所不同。
可以使用LENGTH()和CHAR_LENGTH()统计字符串的长度:
- LENGTH()是按照字节来统计的,
- CHAR_LENGTH()是按照字符来统计的。
2 操作示例
2.1 查看列类型的长度
理论部分可以查看如下两篇官方文档:
https://dev.mysql.com/doc/refman/5.7/en/innodb-row-format.html
https://dev.mysql.com/doc/refman/5.7/en/storage-requirements.html
mysql> SELECT @@innodb_default_row_format;
+-----------------------------+
| @@innodb_default_row_format |
+-----------------------------+
| dynamic |
+-----------------------------+
1 row in set (0.00 sec)
mysql>
mysql> use ustc;
Database changed
mysql> CREATE TABLE cndba(c1 int);
Query OK, 0 rows affected (0.07 sec)
mysql> show create table cndba/G
*************************** 1. row ***************************
Table: cndba
Create Table: CREATE TABLE `cndba` (
`c1` int(11) DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4
1 row in set (0.00 sec)
mysql> insert into cndba values(1);
Query OK, 1 row affected (0.02 sec)
我们这里可以看到,在utf8mb4 字符集下,INT 类型占1个字符(4个字节)。
mysql> select length(c1) from cndba;
+------------+
| length(c1) |
+------------+
| 1 |
+------------+
1 row in set (0.00 sec)
mysql> select char_length(c1) from cndba;
+-----------------+
| char_length(c1) |
+-----------------+
| 1 |
+-----------------+
1 row in set (0.00 sec)
mysql> SELECT * FROM INFORMATION_SCHEMA.INNODB_SYS_TABLES WHERE NAME LIKE 'ustc/cndba'/G
*************************** 1. row ***************************
TABLE_ID: 43
NAME: ustc/cndba
FLAG: 33
N_COLS: 4
SPACE: 33
FILE_FORMAT: Barracuda
ROW_FORMAT: Dynamic
ZIP_PAGE_SIZE: 0
SPACE_TYPE: Single
1 row in set (0.00 sec)
mysql> SHOW TABLE STATUS/G
*************************** 1. row ***************************
Name: cndba
Engine: InnoDB
Version: 10
Row_format: Dynamic
Rows: 1
Avg_row_length: 16384
Data_length: 16384
Max_data_length: 0
Index_length: 0
Data_free: 0
Auto_increment: NULL
Create_time: 2023-10-14 23:58:19
Update_time: 2023-10-15 00:04:09
Check_time: NULL
Collation: utf8mb4_general_ci
Checksum: NULL
Create_options:
Comment:
1 row in set (0.00 sec)
注意这里的16384, 是65535/4 的值。
其他类型的长度可以参考博客:
2.2 验证最大长度
VARCHAR(M) 能设置的最大长度
M 限制了 VARCHAR 能存储的字符串的最大长度,注意,是字符,不是字节,其有效值范围为 0 ~ 65535。
在 latin1 字符集下,M 最大就只能设置为 65532。
mysql> create table t (c1 varchar(65535)) 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
mysql> create table t (c1 varchar(65532)) charset latin1;
Query OK, 0 rows affected (0.04 sec)
但是在utf8mb4 字符集下,建表时貌似没有实际进行检测,实际上并不是这样:
mysql> create table t (c1 varchar(1165533) not null) charset utf8mb4;
Query OK, 0 rows affected, 1 warning (0.07 sec)
mysql> create table t3 (c1 varchar(1111165533) not null) charset utf8mb4;
Query OK, 0 rows affected, 1 warning (0.06 sec)
mysql> create table t4 (c1 varchar(1111165533) ) charset utf8mb4;
Query OK, 0 rows affected, 1 warning (0.05 sec)
在低版本的MySQL中会有错误提示:
mysql> create table t (c1 varchar(65533) not null) charset utf8mb4;
ERROR 1074 (42000): Column length too big for column 'c1' (max = 16383); use BLOB or TEXT instead
但是在5.7 后期的版本中,会自动转换成text类型:
mysql> select @@version;
+------------+
| @@version |
+------------+
| 5.7.25-log |
+------------+
1 row in set (0.00 sec)
mysql> create table t3(name varchar(65535));
Query OK, 0 rows affected, 1 warning (0.07 sec)
mysql> show warnings;
+-------+------+-----------------------------------------------+
| Level | Code | Message |
+-------+------+-----------------------------------------------+
| Note | 1246 | Converting column 'name' from VARCHAR to TEXT |
+-------+------+-----------------------------------------------+
1 row in set (0.00 sec)
表创建之后,实际上是有个警告的,直接对列进行类型转换:
mysql> desc t3/G
*************************** 1. row ***************************
Field: name
Type: mediumtext
Null: YES
Key:
Default: NULL
Extra:
1 row in set (0.00 sec)
这里的类型也验证,mysql 自动将表T3 的列从varchar 转换成了mediumtext。
这里这里弄清楚之后就很好进一步验证了,我们创建个多列的表,长度加起来超过65535即可:
mysql> CREATE TABLE t1 (a VARCHAR(10000), b VARCHAR(10000), c VARCHAR(10000), d VARCHAR(10000), e VARCHAR(10000), f VARCHAR(10000), g VARCHAR(6000));
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时,varchar会自动转换成text。
- 当表有多列的情况,所有列加起来的长度,不能超过65535,这里不包括TEXT、BLOB。
版权声明:本文为博主原创文章,未经博主允许不得转载。