一:引言

  1118 - 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
翻译:1118 -行太大。所用表类型的最大行大小(不包括BLOBs)是65535。这包括存储开销,请查看手册。您必须将一些列更改为TEXT类型或BLOBs类型

  这个错误我相信大家都遇到过,当数据库里面的字段特别多且每个字段占的存在范围字节也特别大就会有可能出现当前错误,主要原因是行大小超过了65535个字节

二:列数限制

技巧💡

简单来说,mysql规定是4096列,但是依赖存储引擎(innodb 1017列)、行大小限制(比如行大小到了限制,但是列没到)等。

MySQL的每个表有4096列的硬限制,但给定表的有效最大值可能更少。确切的列限制取决于几个因素:
①:表的最大行大小约束列的数量(可能还有大小),因为所有列的总长度不能超过此大小。
— 说明:可能列没达到最大,但行大小已经提前限制了表继续创建字段了
②:各个列的存储要求限制了给定最大行大小内的列数。某些数据类型的存储要求取决于存储引擎、存储格式和字符集等因素。
③:存储引擎可能会施加限制表列计数的其他限制。例如InnoDB每个表的限制为1017列。

二:行大小限制

**①:MySQL表具有65535字节的最大行大小限制,即使存储引擎能够支持更大的行也是如此。
在MySQL的设定中单行数据最大能存储65535byte的数据(注意是byte,而不是字符)。
②:对于默认的16KB InnoDB页大小,最大行大小略小于8KB 。对于64KB页,最大行大小略小于16KB。 如果包含可变长度列(例如:text)的InnoDB行超过最大行大小,InnoDB选择可变长度列进行页外存储。 主要是说明,一个数据页,至少会有2行记录。。如果超过一半,则会变成溢出页。

行最大字节数为什么是65535?💡

65535是mysql单行的最大长度(不包含blob和text等类型的情况下)
mysql表里单行中的所有列加起来(不考虑其他隐藏列和记录头信息) ,占用的最大长度是65535个字节.所以字节数len(content) + bitmap(isNull) + content。
如果还有int的列,那它占用4个字节,bigint占用8个字节,字段越多,留给单个varchar列的空间就越少

image.png

varchar(M)占用的字节数怎么计算?💡

首先,要明确几个概念。 varchar(M)中的M,是指M个字符。而不是字节。所以M个字符对应的字节与字符集有关。
W: 即假设某个字符集最多需要W字节来表示一个字符。
utf8mb4字符集中的W就是4
utf8字符集中W就是3
gbk字符集中的W就是2
ascii字符集中的W就是1
M: varchar(M)中的M,即 M个字符。那么M个字符,如果都填充满,占用的字节是 M*W
L: 变长字段真实的存储字符串占用的字节数。明显 L <= W*M

首先,现在我们知道,记录的额外信息,是紧凑的,没有额外的分隔符,那我们怎么知道,第一个字节是哪个字段的长度呢?又怎么确定,这个列是1个字节还是2个字节?这里就涉及到尽可能较少占用空间。

为什么前缀长度,最大用2个字节💡

为什么长度前缀 1 或 2 个字节就够用了呢, 因为 2 个字节的话, 2^16 = 65536, 这已经超过 mysql 行最大字节数 65535 的限制了, 所以 1 到 2 个字节就够用了。

那如果确定1个字节还是2个字节来表示某个变长列的长度呢?这里定义了一套规则,目的了尽可能减少占用空间。

首先,强调一点,为了减少占用空间,我们要充分利用表结构。比如表定义已经明确该列固定长度是20了,那么我们就不用每行都去存储这个长度了。(REDUNDANT就不够智能,后续说明。)

我们知道,1个字节,可以存储的大小为 2^8 = 256,可以存储数据到255。2^16 = 65536,可以存储到65535的大小。

  1. 很容易想到,先看表结构,如果表结构定义即(M × W)<=255,那么直接用1个字节来存储。因为实际存储长度最大,也就是255个字节。
  2. 如果表结构定义, >255呢?
    1. 粗暴的做法,是直接用2个字节。但是这个还有优化空间吗?
    2. 更精细化的,
      1. 如果实际存储L <= 127,那么我们就只定义1个字节就好
      2. 如果实际存储L >=127, 那么我们就使用2个字节。

这里为什么是判断L<=127呢?💡

这是因为,我们会将第一个字节的首位来区分,是1个字节还是2个字节。 如果高位是1,就代表这个变长的长度是2个字节。 2^7=128.正好存储的极限是127.

总结下这个规则:

  1. 先看表结构定义, MxW <=255.直接用1个字节来存储。
  2. 表结构定义(MxW >255),那么判断最高位是0还是1,如果是1,代表是2个字节来存储数据。

疑问💡

这里还有个有意思的优化,mysql在存储变长字段长度的顺序,是逆序的,并不是按照字段的顺序。主要是为了尽可能使用到缓存。这里我不是很理解,这整个不是都加载到内存了吗?有什么区别吗?

varchar(M) 能存多少个字符,为什么提示最大16383? (utf-8mb4字符集,最大占4个字节)

要求出这个M,首先不考虑其他列的情况,很明显,这里肯定能达到2个字节。按上限来计算。即M x W >255.
(65535 - 2 )/4 = 16383.75.
65535,是每个行的上限, [^1]
这里-2,是因为varchar 的变长长度,存储2个字节。
除4,是因为真实占用的字符M, 即每个字符要占用4个字节。所以最大16383个字节。
当然,这里只是说明了只有1列,没有NULL值等情况。而且也不考虑内部碎片等问题。

表数量限制

mysql没限制表的数量限制,取决于文件系统的文件数量限制。但是有可能会受限于存储引擎。如innbodb存取引擎的限制是 40亿张表。。

资料

MySQL :: MySQL 8.0 Reference Manual :: 8.4.7 Limits on Table Column Count and Row Size

MySQL表列数和行大小限制 - 蚂蚁小哥 - 博客园