VarChar 的行大小不超过

Row size doesn't exceed for VarChar

我的table:

create table test( pk bigint primary key,
value1 varchar(255),
value2 varchar(255),
value3 varchar(255),
value4 varchar(255),
value5 varchar(255),
value6 varchar(255),
value7 varchar(255),
value8 varchar(255),
value9 varchar(255),
value10 varchar(255),
value11 varchar(255),
);

插入查询:

insert into test values(1, '‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱','‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱','‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱','‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱','‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱','‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱','‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱','‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱','‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱','‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱','‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱‱');

我的页面大小是 16KB。所以我的 table 中的一行最多可以包含 8192bytes(即 8KB)。

我创建了 11 VARCHAR 列(每列 255 个字符),其中这 11 列最多可以容纳 255*11 = 2805 个字符。

如果我存储 2805 - 3byte 个字符,它将需要 (255*11*3) = 8415bytes,这超过了最大行大小的限制 (8192bytes)。

现在我尝试插入上面的单行查询,其中有 8415bytes 数据。但是我的 MYSQL 没有抛出接受该插入查询的错误。

3 byte character - ‱

Row Format - DYNAMIC

Collation - UTF8mb3

Character set - utf8_general_ci

Mysql - 5.7

Update: Same thing is happening for CHAR column too(changed VarChar to Char), which is Fixed-length column.

你误解了 innodb 行大小限制的描述。引自 mysql manual(重点是我的):

The maximum row length, except for variable-length columns (VARBINARY, VARCHAR, BLOB and TEXT), is slightly less than half of a page for 4KB, 8KB, 16KB, and 32KB page sizes. For example, the maximum row length for the default innodb_page_size of 16KB is about 8000 bytes. ...

If a row is less than half a page long, all of it is stored locally within the page. If it exceeds half a page, variable-length columns are chosen for external off-page storage until the row fits within half a page, as described in Section 14.12.2, “File Space Management”.

由于您的字段是 varchar(可变长度 fiekd 类型),超过半页大小限制的数据只是存储在另一个页外位置,因此您的 sql 语句是正确的。

编辑

对于 char 个字段,行为取决于行格式和使用的字符集。

一个char字段的长度在字符数方面是固定的,但根据字符集,字节长度可能是固定的(例如latin1是固定的1字节/字符),或可变的(例如 utf8mb3 是可变长度 1-3 字节/字符)。

对于 compact 行格式,字符集是无关紧要的,如果最大可能字节长度超过了当您要创建 table.

对于dynamic行格式,如果字符集是固定长度且字节长度超过数据页限制,那么在创建table时会出错。但是,如果字符集是可变长度的,则数据将存储在溢出页面中。

正如 SHADOW 对 VARHCAR 列所说的那样

If a row is less than half a page long, all of it is stored locally within the page. If it exceeds half a page, variable-length columns are chosen for external off-page storage until the row fits within half a page

对于 CHAR

InnoDB encodes fixed-length fields greater than or equal to 768 bytes in length as variable-length fields, which can be stored off-page. For example, a CHAR(255) column can exceed 768 bytes if the maximum byte length of the character set is greater than 3, as it is with utf8mb4. https://forums.mysql.com/read.php?24,645115,645215#msg-645215

其中 mysql 在内部将固定长度字段转换为可变长度字段 https://dev.mysql.com/doc/refman/5.6/en/storage-requirements.html

Internally, for variable-length character sets such as utf8mb3 and utf8mb4, InnoDB attempts to store CHAR(N) in N bytes by trimming trailing spaces. If the byte length of a CHAR(N) column value exceeds N bytes, trailing spaces are trimmed to a minimum of the column value byte length. The maximum length of a CHAR(N) column is the maximum character byte length × N.

A minimum of N bytes is reserved for CHAR(N). Reserving the minimum space N in many cases enables column updates to be done in place without causing index page fragmentation. By comparison, CHAR(N) columns occupy the maximum character byte length × N when using the REDUNDANT row format.

-- https://dev.mysql.com/doc/refman/5.6/en/innodb-row-format.html#innodb-compact-row-format-characteristics

以上指的是ROW_FORMAT = COMPACT、DYNAMIC、COMPRESSED(压缩前)。它正在谈论 on-page 存储 CHAR