ChatGPT解决这个技术问题 Extra ChatGPT

MySQL:大型 VARCHAR 与 TEXT?

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

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

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

J
Justin Johnson

TEXT 和 BLOB 可以通过存储在表之外,而表中只有一个指向实际存储位置的指针。它的存储位置取决于很多因素,例如数据大小、列大小、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
a
ashleedawg

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

VARCHAR(X) 最大长度:可变,最大 65,535 字节 (64KB) 大小写:用户名、电子邮件、国家、主题、密码 TEXT 最大长度:65,535 字节 (64KB) 大小写:消息、电子邮件、评论、格式化文本、html、代码、图像、链接 MEDIUMTEXT 最大长度:16,777,215 字节 (16MB) 案例:大型 json 正文、中短篇书籍、csv 字符串 LONGTEXT 最大长度:4,294,967,29 字节 (4GB) 案例:教科书、程序、多年的日志文件,哈利波特与火焰杯,科研记录

有关 this question 的更多信息。


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

只是为了澄清最佳实践:

文本格式的消息几乎总是应该存储为 TEXT(它们最终会变得任意长) 字符串属性应该存储为 VARCHAR(目标用户名、主题等)。

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

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


那么,您会建议如何处理像来自magnet: URL 的超大 URL?它们可以比 255 个字符长得多。
K
Kosta Kontos

简短的回答:没有实用、性能或存储方面的差异。

长答案:

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

对于 VARCHAR 中的较小限制,与 TEXT 相比有一些优势。

“更小”表示 191、255、512、767 或 3072 等,具体取决于版本、上下文和字符集。

INDEX 限制了可以索引的列的大小。 (767 或 3072 字节;这取决于版本和设置)

由复杂 SELECT 创建的中间表以两种不同的方式处理 - MEMORY(更快)或 MyISAM(更慢)。当涉及“大”列时,会自动选择较慢的技术。 (8.0 版中有重大变化;所以这个项目符号可能会发生变化。)

与上一项相关,所有 TEXT 数据类型(与 VARCHAR 相对)都直接跳转到 MyISAM。也就是说,对于生成的临时表,TINYTEXT 自动比等效的 VARCHAR 更差。 (但这会将讨论引向第三方!)

VARBINARY 类似于 VARCHAR; BLOB 就像 TEXT。

反驳其他答案

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

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

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


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

免责声明:我不是 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 内联存储在表中。
@dotancohen 我在这里找到了一个来源,解释说使用 InnoDB 存储可变长度数据可能会有所不同(可以存储在外部或行内)mysqlserverteam.com/externally-stored-fields-in-innodb
G
Gerry

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

(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 是可变长度的。
A
Achraf Almouloudi

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

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

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

Blob 的速度要慢得多,因此只有在您没有太多数据(如 10000 张图像,这将花费 10000 条记录)时才使用它。

请遵循以下提示以获得最大速度和性能:

对姓名、标题、电子邮件使用 varchar 对大数据使用 Text 将不同表中的文本分开 对 ID(例如电话号码)使用 Left Join 查询 如果您要使用 Blob,请应用与 Text 中相同的提示

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


V
Viktor Joras

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

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

如果您仅将您的字段用于存档

你不关心数据速度检索

您关心速度,但您将在搜索查询中使用运算符“%LIKE%”,因此索引不会有太大帮助

您无法预测数据长度的限制

而不是去文本。


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

只是对这里这么多答案的更正,即使聚会有点晚了。

MySQL 可以根据其文档对文本字段进行完全索引。

提供的链接 https://dev.mysql.com/doc/refman/5.6/en/column-indexes.html

总体 Varchar 字段的写入时间比 Text 字段要长,但只有在您有大量写入请求时才重要