在什么情况下 BLOB 和 TEXT 在线存储在 InnoDB 上?

Eva*_*oll 6 mysql innodb storage database-internals blob

我在谷歌上搜索过这个但找不到,你可以看到Rick James在这里提到它。

......BLOBTEXT并不总是分开存放

在回答什么是MySQL的VARCHAR和TEXT数据类型之间的区别?说,

InnoDB 与 类似VARCHAR,但将完整TEXT字段存储在记录之外。

对于这种立场,这并不是唯一获得大量支持的答案。从 StackOverflow你可以找到一个有754 个赞的答案,它说得很清楚,

TEXTBLOB存储在表外,表只有一个指向实际存储位置的指针。

VARCHAR与表内联存储。VARCHAR当大小合理时更快,权衡更快取决于您的数据和您的硬件,您希望使用您的数据对现实世界的场景进行基准测试。

这里评论链接到一个邮件列表上的帖子,上面写着

MyISAM 放置TEXTBLOB“内联”。如果您正在搜索表(范围扫描/表扫描),那么您就是在“跨过那些牛田”——磁盘 I/O 的成本很高。也就是说,在这种情况下,内联 blob 的存在会损害性能。

InnoDB 只放入 767 字节的 aTEXTBLOBinline,其余部分放入其他块。这是一种有时会有所帮助,有时会损害性能的妥协。

我看过其他帖子,讨论在某些限制下存储文本和 blob 吗?限制是什么?InnoDB 什么时候(如果有的话)在行中存储 blob 和文本?

Ric*_*mes 9

请记住,有 4 种“行格式”。then 之间的主要区别与处理列的宽度有关。

参考指向 2010 年初写的答案,几个月前DYNAMICCOMPRESSED并在“InnoDB 插件”中引入。

所以,我声称其他问答已经过时了! 那就是 754 个赞成票不再有效。

以下是一些“当前”手册参考:

(强调我的)

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

诸如 BLOB和 VARCHAR 之类的列太长而无法放入 B 树页面,它们存储在单独分配的磁盘页面上,称为溢出页面。

来自https://dev.mysql.com/doc/refman/5.6/en/innodb-row-format-dynamic.html

当使用ROW_FORMAT=DYNAMIC 或 ROW_FORMAT=COMPRESSED创建表时,InnoDB 可以完全离页存储长可变长度列值(对于 VARCHAR、VARBINARY 和 BLOB 和 TEXT 类型),聚集索引记录仅包含 20-指向溢出页的字节指针。

[动态和压缩] 当行太长时,InnoDB 会选择最长的列进行页外存储,直到聚集索引记录适合 B 树页面。小于或等于 40 字节的TEXT 和 BLOB 列总是内联存储

动态格式是基于这个想法,如果一个长的数据值的一部分存储关闭网页,它通常是最有效的所有存储关闭页的价值。使用 DYNAMIC 格式,较短的列可能会保留在 B 树节点中,从而最大限度地减少任何给定行所需的溢出页数。

压杆行格式使用类似的内部细节关闭页仓储为一体的动态记录格式

来自https://dev.mysql.com/doc/refman/5.6/en/innodb-physical-record.html(即使是大的CHAR也可能被视为TEXT):

InnoDB [所有格式?] 将长度大于或等于 768 字节的固定长度字段编码为可变长度字段,可以在页外存储。例如,如果字符集的最大字节长度大于 3,则CHAR(255)列可以超过 768 个字节,就像使用 utf8mb4 一样。

ROW_FORMAT=DYNAMIC 和 ROW_FORMAT=COMPRESSED 以与 ROW_FORMAT=COMPACT 相同的方式处理 CHAR 存储。

(链接适用于 5.6,但我认为该文本至少适用于较新的版本。)

我没有看到任何具体的说法,VARCHAR(...)并且*TEXT处理方式不同。


aku*_*sky 5

对于 InnoDB,规则是这样的:

  • 记录不能碎片化。
  • 一页中必须至少容纳两条记录。
  • 如果记录大小小于 ~7k,则所有字段值都存储在页中。
  • 如果记录大小超过 ~7k,则前 768(COMPACT格式)或 20 字节(DYNAMIC格式)存储在页中。其余部分存储在页外。

如何验证。

CREATE TABLE `t1` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `name` text,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1


mysql> insert into t1(name) select repeat('a', 10);
Query OK, 1 row affected (0.02 sec)
Records: 1  Duplicates: 0  Warnings: 0

mysql> insert into t1(name) select repeat('a', 8000);
Query OK, 1 row affected (0.00 sec)
Records: 1  Duplicates: 0  Warnings: 0
Run Code Online (Sandbox Code Playgroud)

然后t1.ibdstream_parser解析。

stream_parser -f t1.ibd
Run Code Online (Sandbox Code Playgroud)

检查 PRIMARY 索引页的内容:

# hexdump -C pages-t1.ibd/FIL_PAGE_INDEX/0000000000000046.page
00000000  97 e5 5e 36 00 00 00 03  ff ff ff ff ff ff ff ff  |..^6............|
00000010  00 00 00 00 00 27 b9 44  45 bf 00 00 00 00 00 00  |.....'.DE.......|
00000020  00 00 00 00 00 18 00 02  1f f3 80 04 00 00 00 00  |................|
00000030  00 a2 00 02 00 01 00 02  00 00 00 00 00 00 00 00  |................|
00000040  00 00 00 00 00 00 00 00  00 2e 00 00 00 18 00 00  |................|
00000050  00 02 00 f2 00 00 00 18  00 00 00 02 00 32 01 00  |.............2..|
00000060  02 00 1c 69 6e 66 69 6d  75 6d 00 03 00 0b 00 00  |...infimum......|
00000070  73 75 70 72 65 6d 75 6d  0a 00 00 00 10 00 23 80  |supremum......#.|
00000080  00 00 01 00 00 00 00 05  10 ae 00 00 01 22 01 10  |............."..|
00000090  61 61 61 61 61 61 61 61  61 61 40 9f 00 00 00 18  |aaaaaaaaaa@.....| <- this is the first record
000000a0  ff ce 80 00 00 02 00 00  00 00 05 11 af 00 00 01  |................|
000000b0  23 01 10 61 61 61 61 61  61 61 61 61 61 61 61 61  |#..aaaaaaaaaaaaa| <- this is the beginning of the second record
000000c0  61 61 61 61 61 61 61 61  61 61 61 61 61 61 61 61  |aaaaaaaaaaaaaaaa|
* <- The star means identical strings are omitted, -v will show full output.
00001ff0  61 61 61 00 00 00 00 00  00 00 00 00 00 00 00 00  |aaa.............|
00002000  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
*
00003ff0  00 00 00 00 00 70 00 63  97 e5 5e 36 00 27 b9 44  |.....p.c..^6.'.D|
00004000  97 e5 5e 36 00 00 00 03  ff ff ff ff ff ff ff ff  |..^6............|
00004010  00 00 00 00 00 27 b9 44  45 bf 00 00 00 00 00 00  |.....'.DE.......|
00004020  00 00 00 00 00 18 00 02  1f f3 80 04 00 00 00 00  |................|
00004030  00 a2 00 02 00 01 00 02  00 00 00 00 00 00 00 00  |................|
00004040  00 00 00 00 00 00 00 00  00 2e 00 00 00 18 00 00  |................|
00004050  00 02 00 f2 00 00 00 18  00 00 00 02 00 32 01 00  |.............2..|
00004060  02 00 1c 69 6e 66 69 6d  75 6d 00 03 00 0b 00 00  |...infimum......|
00004070  73 75 70 72 65 6d 75 6d  0a 00 00 00 10 00 23 80  |supremum......#.|
00004080  00 00 01 00 00 00 00 05  10 ae 00 00 01 22 01 10  |............."..|
00004090  61 61 61 61 61 61 61 61  61 61 40 9f 00 00 00 18  |aaaaaaaaaa@.....|
000040a0  ff ce 80 00 00 02 00 00  00 00 05 11 af 00 00 01  |................|
000040b0  23 01 10 61 61 61 61 61  61 61 61 61 61 61 61 61  |#..aaaaaaaaaaaaa|
000040c0  61 61 61 61 61 61 61 61  61 61 61 61 61 61 61 61  |aaaaaaaaaaaaaaaa|
*
00005ff0  61 61 61 00 00 00 00 00  00 00 00 00 00 00 00 00  |aaa.............|
00006000  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
*
00007ff0  00 00 00 00 00 70 00 63  97 e5 5e 36 00 27 b9 44  |.....p.c..^6.'.D|
00008000
Run Code Online (Sandbox Code Playgroud)

这是COMPACT格式。对于DYNAMIC(除外COMPRESSED)程序是相同的。