MySQL:大型 VARCHAR 与 TEXT?

Posted

技术标签:

【中文标题】MySQL:大型 VARCHAR 与 TEXT?【英文标题】:MySQL: Large VARCHAR vs. TEXT? 【发布时间】:2011-01-02 16:02:41 【问题描述】:

我在 mysql 中有一个消息表,用于记录用户之间的消息。除了典型的 id 和消息类型(所有整数类型)之外,我需要将实际的消息文本保存为 VARCHAR 或 TEXT。我设置了 3000 个字符的前端限制,这意味着消息永远不会被插入到数据库中。

是否有使用 VARCHAR(3000) 或 TEXT 的理由?写 VARCHAR(3000) 有点违反直觉。我已经在 Stack Overflow 上浏览过其他类似的帖子,但如果能获得特定于这种常见消息存储类型的视图会很好。

【问题讨论】:

有点老了,但我来到这里是因为我遇到了一个让我想到这个的问题。在我的例子中,我的前端表单限制为 2,000 个字符,但我的存储方法中隐含的编码将国际字符编码为多个字符(显然每个字符可以包含 3 到 12 个字符)。所以我的2000突然变成了24000。需要考虑的事情...... 我发现文本对于许多并发插入来说要快得多。 @JamesS: utf8mb4... >. @RickJames 考虑发布更新的答案,而不是关闭问题 @YvetteColomb - 我添加了一个答案。我主要想摆脱已接受的答案,因为它已过时。我参加问答环节是因为有人引用了不正确的信息,说“754 票,所以一定是对的”。好的,我也编辑了已批准的答案。 (虽然感觉不妥。) 【参考方案1】:

TEXTBLOB 可以通过存储在表外,表中只有一个指向实际存储位置的指针。它的存储位置取决于很多因素,例如数据大小、列大小、row_format 和 MySQL 版本。

VARCHAR 与表内联存储。 VARCHAR 在大小合理的情况下会更快,其中的权衡是否会更快取决于您的数据和硬件,您希望使用您的数据对真实场景进行基准测试。

【讨论】:

+1:如果经常检索数据(包括在大多数查询中),VARCHAR(内联存储)通常更快。但是,对于通常不会检索到的大量数据(即没有被任何查询引用),那么最好不要将数据内联存储。对于内联存储的数据,行大小有上限。 @Pacerier:避免“内联”存储的确切好处是增加了可以存储在块中的行数,这意味着表行在 InnoDB 缓冲区缓存中占用的块更少(更小的内存占用),并且意味着更少的块传输到磁盘和从磁盘传输(减少 I/O)。但是,如果存储“行外”的列在很大程度上未被查询引用,这只是性能优势。如果大多数查询都引用了那些“行外”列,那么这种好处就会在很大程度上消失。如果列适合最大行大小并且经常被引用,则首选内联。 “大小合理时 VARCHAR 更快”。什么是“合理”的字符数,100? 1000? 100,000? 这个答案对于 InnoDB 是不正确的。如果给定行上的值适合页面大小(16KB 并且每个页面必须至少包含两行),则 VARCHAR 和 BLOB/TEXT 都与其他列内联存储。如果字符串太大,它会溢出到其他页面。详细解释见mysqlperformanceblog.com/2010/02/09/blob-storage-in-innodb。【参考方案2】:

你能预测用户输入会持续多长时间吗?

VARCHAR(X)

最大长度:可变,最多 65,535 字节 (64KB)大小写:用户名、电子邮件、国家/地区、主题、密码


TEXT

最大长度: 65,535 字节 (64KB)案例: 消息、电子邮件、cmets、格式化文本、html、代码、图像、链接


MEDIUMTEXT

最大长度: 16,777,215 字节 (16MB)案例: 大型 json 正文、短到中等长度的书籍、csv 字符串


LONGTEXT

最大长度: 4,294,967,29 字节 (4GB)案例: 教科书、程序、多年的日志文件、哈利波特与火焰杯、科学研究记录

有更多关于this question的信息。

【讨论】:

可预测性在这里确实是一个副项目。实际上,最大预期长度应该是决定因素。您提到的更可预测的项目只是这样,因为它们比其他项目 @andrew-barber 这就是我的意思。所有其他帖子都很好地解释了差异,但没有说明您实际上必须在两者之间做出选择的情况。我试图指出将 varchar 用于可预测的短是一个不错的选择,而使用任意长的文本是一个不错的选择。【参考方案3】:

只是为了阐明最佳实践:

    文本格式的消息几乎应始终存储为 TEXT(它们最终会变得任意长)

    字符串属性应存储为 VARCHAR(目标用户名、主题等...)。

我知道您有前端限制,这很好,直到没有。 *grin* 诀窍是将数据库与连接到它的应用程序分开。仅仅因为一个应用程序对数据进行了限制,并不意味着数据在本质上是有限的。

是什么让消息本身不能超过 3000 个字符?如果它只是一个任意的应用程序约束(例如,对于文本框或其他东西),请在数据层使用 TEXT 字段。

【讨论】:

【参考方案4】:

免责声明:我不是 MySQL 专家……但这是我对这些问题的理解。

我认为 TEXT 存储在 mysql 行之外,而我认为 VARCHAR 存储为行的一部分。 mysql 行有一个最大行长度.. 所以你可以通过使用 VARCHAR 来限制你可以在一行中存储多少其他数据。

另外由于 VARCHAR 构成了行的一部分,我怀疑查看该字段的查询会比使用 TEXT 块的查询稍快。

【讨论】:

行长度限制为 65,535 字节 [dev.mysql.com/doc/refman/5.0/en/column-count-limit.html]。如果您的列是 utf8 编码的,这意味着 3000 个字符的 varchar 列最多可以占用 9000 个字节。 UTF-8 字符最多可以有 4 个字节,所以我认为您的意思是 12,000 个字节(除非这里有一些我不理解的 MySQL 内容)。 @raylu MySQL 的 UTF-8 是“假 UTF-8”,因为它最多只支持每个字符 3 个字节,因此无法在 MySQL 的 UTF-8 中直接存储 BMP 平面之外的 unicode 字符.这在 MySQL 5.5 中已修复。 我相信这个断言只对 MyISAM 有效。我找不到明确的来源,但我相信 InnoDB 也将 TEXT inline 存储在表中。 @dotancohen 我在这里找到了一个来源,解释说使用 InnoDB 存储可变长度数据可能会有所不同(可以存储在外部或行内)mysqlserverteam.com/externally-stored-fields-in-innodb【参考方案5】:

简答:没有实用、性能或存储方面的区别。

长答案:

VARCHAR(3000)(或任何其他较大的限制)和TEXT 之间基本上没有区别(在 MySQL 中)。前者将截断 3000 个字符;后者将在 65535 字节处截断。 (我区分 bytescharacters 因为一个字符可以占用多个字节。)

VARCHAR 的限制更小,与TEXT 相比有一些优势。

“更小”是指 191、255、512、767 或 3072 等,具体取决于版本、上下文和CHARACTER SETINDEXes 限制了可以索引的列的大小。 (767 或 3072 字节;这取决于版本和设置) 由复杂SELECTs 创建的中间表以两种不同的方式处理——MEMORY(更快)或 MyISAM(更慢)。当涉及“大”列时,会自动选择较慢的技术。 (8.0 版中有重大变化;因此此项目符号可能会发生变化。) 与上一项相关,所有TEXT 数据类型(相对于VARCHAR)直接跳转到MyISAM。也就是说,对于生成的临时表,TINYTEXT 自动比等效的 VARCHAR 更差。 (但这会将讨论引向第三方!) VARBINARY 就像 VARCHAR; BLOB 就像 TEXT

反驳其他答案

最初的问题问了一件事(使用哪种数据类型);接受的答案回答了其他问题(非记录存储)。这个答案现在已经过时了。

当这个线程开始回答时,InnoDB 中只有两种“行格式”。不久之后,又引入了两种格式(DYNAMICCOMPRESSED)。

TEXTVARCHAR() 的存储位置基于大小,而不是数据类型名称。有关大型文本/blob 列的开/关存储的更新讨论,请参阅this

【讨论】:

@KostaKontos - 感谢您的称赞和错字修复。当我看到需要更好的答案时,我会添加一个答案,即使 8 年和 800 次投票为时已晚。【参考方案6】:

前面的答案对主要问题的坚持不够:即使在非常简单的查询中,例如

(SELECT t2.* FROM t1, t2 WHERE t2.id = t1.id ORDER BY t1.id) 

可能需要临时表,如果涉及VARCHAR字段,则在临时表中转换为CHAR字段。因此,如果您的表中有 500 000 行带有 VARCHAR(65000) 字段,则仅此列将使用 6.5*5*10^9 字节。此类临时表无法在内存中处理并写入磁盘。预计其影响将是灾难性的。

来源(带有指标):https://nicj.net/mysql-text-vs-varchar-performance/ (这是指“标准”(?)MyISAM存储引擎中TEXTVARCHAR的处理。在其他方面可能有所不同,例如,InnoDB。)

【讨论】:

InnoDB:同样适用于 5.7 版。在 8.0 中,varchar temps 是可变长度的。【参考方案7】:

Varchar 用于电子邮件地址等小数据,而 Text 用于新闻文章等更大的数据,Blob 用于图像等二进制数据。

Varchar 的性能更强大,因为它完全从内存中运行,但如果数据太大,例如varchar(4000),则不会出现这种情况。

另一方面,文本不会粘在内存中,并且会受到磁盘性能的影响,但您可以通过将文本数据分离到单独的表中并应用左连接查询来检索文本数据来避免这种情况。

Blob 的速度要慢得多,因此请仅在您没有太多数据(例如 10000 张图像需要 10000 条记录)时才使用它。

遵循这些提示以获得最大速度和性能:

    使用 varchar 表示姓名、头衔、电子邮件

    对大数据使用文本

    不同表格中的单独文本

    对电话号码等 ID 使用左连接查询

    如果您要使用 Blob,请应用与 Text 中相同的提示

这将使对数据 >10 M 且保证大小高达 10GB 的表的查询花费几毫秒。

【讨论】:

【参考方案8】:

VARCHAR 和 TEXT 之间存在巨大的区别。虽然 VARCHAR 字段可以被索引,但 TEXT 字段不能。 VARCHAR 类型的字段是内联存储的,而 TEXT 是脱机存储的,只有指向 TEXT 数据的指针实际存储在记录中。

如果您必须为字段建立索引以便比使用 VARCHAR 更快地搜索、更新或删除,无论它有多大。 VARCHAR(10000000) 永远不会与 TEXT 字段相同,因为这两种数据类型在本质上是不同的。

如果您将字段仅用于存档 你不关心数据 速度检索 你关心速度,但你会使用运算符 '%LIKE%' 在您的搜索查询中,因此索引不会有太大帮助 你 无法预测数据长度的限制

而不是选择 TEXT。

【讨论】:

部分误导信息:TEXT 列不能作为整体索引。当您在索引中包含 TEXT 列时,您必须指定长度。此外,在 VARCHAR > 255 的情况下,VARCHAR 也无法完整索引,因为索引大小存在最大长度。

以上是关于MySQL:大型 VARCHAR 与 TEXT?的主要内容,如果未能解决你的问题,请参考以下文章

mysql中char,varchar与text类型的区别

mysql中char,varchar与text类型的区别和选用

mysql中char,varchar与text类型的区别和选用

MySQL中char与varchar有什么区别

mysql char与varchar区别

何时在 mysql 中使用 TEXT 而不是 VARCHAR [重复]