标签:
今天被开发提交的DDL变更再次困惑,表中字段较多,希望将已有的两个varchar(4000)字段改为varchar(20000),我想innodb对varchar的存储不就是取前768字节记录当前行空间嘛,所以变更不会有任何问题的,但铁打的事实给了我结结实实的一个巴掌,直接报错,现在回放下这个错误!
模拟测试:
CREATE TABLE `ttt` (
`id` DOUBLE ,
`select_type` VARCHAR (57),
`table` VARCHAR (192),
`type` VARCHAR (30),
`possible_keys` VARCHAR (22288),
`key` VARCHAR (192),
`key_len` VARCHAR (22288),
`ref` VARCHAR (3072),
`rows` DOUBLE ,
`Extra` VARCHAR (765)
);
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
看了提示,表的2个varchar字段长度设置过长了,需要改成text,blob之类的类型,修改之后执行成功了。
mysql> use test;
Database changed
mysql>
mysql> CREATE TABLE `ttt` (
-> `id` DOUBLE ,
-> `select_type` VARCHAR (57),
-> `table` VARCHAR (192),
-> `type` VARCHAR (30),
-> `possible_keys` TEXT,
-> `key` VARCHAR (192),
-> `key_len` TEXT,
-> `ref` VARCHAR (3072),
-> `rows` DOUBLE ,
-> `Extra` VARCHAR (765)
-> );
Query OK, 0 rows affected (0.00 sec)
疑惑:varchar(N),这个N不是最大为65535吗?为什么设置成12288就会报错?12288比65535小很多啊。
上官网:http://dev.mysql.com/doc/refman/5.6/en/column-count-limit.html:
Every table (regardless of storage engine) has a maximum row size of 65,535 bytes. Storage engines may place additional constraints on this limit, reducing the effective maximum row size.
解析:65,535所说明的是针对的是整个表的非大字段类型的字段的bytes总合。
欲看详细分析还要继续往下看
每个表有4096个列的硬性限制,但是到具体表是往往小于这个数字,确切的限制取决于几个相互作用的因素:
每个表(不考虑存储引擎)为65,535字节的最大行大小限制。存储引擎可能会对这个限制进行额外的限制,降低了有效的最大行大小。
最大行长度计算如下:
row length = 1
+ (sum of column lengths)
+ (number of NULL columns + delete_flag + 7)/8
+ (number of variable-length columns)
对于静态表,delete_flag = 1,静态表通过在该行记录一个位来标识该行是否已被删除。 动态表时delete_flag = 0,因为该标记存储在动态行首,动态表具体可以根据row_format判断,详情参考Section 15.2.3, “MyISAM Table Storage Formats”
对于InnoDB表,NULL和NOT NULL列存储大小是一样,因此上述计算并不适用。
以下测试是没有问题的,(32765 + 2 + 32766 + 2 )bytes < 655535
mysql> CREATE TABLE t1
-> (c1 VARCHAR(32765) NOT NULL, c2 VARCHAR(32766) NOT NULL)
-> ENGINE = MyISAM CHARACTER SET latin1;
Query OK, 0 rows affected (0.02 sec)
因为NULL属性需要额外的储存空间,超过了最大65535的限制
mysql> CREATE TABLE t2
-> (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. You have to change some
columns to TEXT or BLOBs
因为变成字段需要占用行内额外的储存空间,所以超过了最大65535的限制
mysql> CREATE TABLE t3
-> (c1 VARCHAR(65535) NOT 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. You have to change some
columns to TEXT or BLOBs
除此之外,一些存储引擎可能会强加限制表中列数的附加限制。如:
如果innodbstrictmode禁用,创建表时使用冗余(REDUNDANT)或紧凑COMPACT格式,如果列超过最大行大小也会成功的定义,只是产生警告:
| Warning | 139 | Row size too large (> 8123). 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.
如果innodbstrictmode禁用,创建表时使用动态(DYNAMIC)或压缩(COMPRESSED)格式,如果列超过最大行大小也会成功的定义,就会直接报错:
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.
每个表都有一个包含表定义的.frm文件。文件定义的内容也会影响到字段数的上限,详情参考Limits Imposed by .frm File Structure
参考:
标签:
原文地址:http://www.cnblogs.com/zhiqian-ali/p/5335107.html