MySQL中VARCHAR和TEXT的区别

470

在MySQL中创建表时,如果有VARCHAR列,我们必须为其设置长度。但对于TEXT类型,我们不需要提供长度。

VARCHARTEXT有什么区别?

2个回答

803

简述

TEXT

  • 最大长度为65535个字符(不可限制最大长度)
  • 占用2+c字节的磁盘空间,其中c为存储字符串的长度。
  • 不能完全成为索引的一部分。需要指定前缀长度。

VARCHAR(M)

  • 可变的最大长度为M个字符
  • M的取值必须在1到65535之间
  • 占用1+c字节(当M≤255时),或者占用2+c字节(当256≤M≤65535时)的磁盘空间,其中c为存储字符串的长度
  • 可以成为索引的一部分

更多细节

TEXT具有固定的最大大小,为2¹⁶-1=65535个字符。
VARCHAR具有可变的最大大小M,最大值为M = 2¹⁶-1
因此,您无法选择TEXT的大小,但可以为VARCHAR选择大小。

另一个区别是,您不能在TEXT列上放置索引(除了全文索引)。
因此,如果您想在列上创建索引,则必须使用VARCHAR。但请注意,索引的长度也是有限制的,因此如果您的VARCHAR列太长,则必须仅在索引中使用前几个字符的VARCHAR列(请参见CREATE INDEX的文档)。

但如果你知道可能输入字符串的最大长度只有M,比如电话号码、姓名之类的内容,你也想使用VARCHAR。那么你可以使用VARCHAR(30)代替TINYTEXT或TEXT,如果有人试图将三本《指环王》的文本保存在你的电话号码列中,你只会存储前30个字符 :)
编辑:如果要存储在数据库中的文本长度超过65535个字符,则必须选择MEDIUMTEXT或LONGTEXT,但要小心:MEDIUMTEXT可存储16 MB的字符串,LONGTEXT可存储4 GB的字符串。如果使用LONGTEXT并通过PHP获取数据(至少如果使用mysqli而不使用store_result),则可能会出现内存分配错误,因为PHP尝试分配4 GB的内存以确保整个字符串可以缓冲。这在PHP以外的其他语言中也可能发生。
然而,在将输入存储到数据库之前,您应该始终检查输入内容(它是否太长?是否包含奇怪的代码?)注意:对于这两种类型,所需的磁盘空间仅取决于存储字符串的长度,而不是最大长度。
例如:如果您使用charset为latin1并在VARCHAR(30)VARCHAR(100)TINYTEXT中存储文本“Test”,则始终需要5个字节(1个字节用于存储字符串长度和每个字符1个字节)。如果您将相同的文本存储在VARCHAR(2000)TEXT列中,它也将占用相同的空间,但在这种情况下,它将是6个字节(2个字节用于存储字符串长度和每个字符1个字节)
要了解更多信息,请查看documentation

最后,我想指出一个注意事项,TEXTVARCHAR都是可变长度数据类型,因此它们很可能会最小化存储数据所需的空间。但这也会带来性能上的折衷。如果您需要更好的性能,则必须使用固定长度类型,例如CHAR。您可以在这里阅读更多信息。


5
@AbcAeffchen,我相信我理解了你的意思。基本上,“fixed max size”意味着你无法设置大小 - 它总是65535,即使你不想支持那么大的尺寸。这意味着TEXT实际上是一个最大大小为2¹⁶-1的VARCHAR字段的简写,忽略索引问题。我理解得对吗? - DemiImp
81
TEXT 相比 VARCHAR 的优势是什么? - Solomon Ucko
5
不,定长的 CHAR 类型并不会提供任何显著的性能改善。(这种说法源于一个有关 MyISAM 表的陈旧传言,即使在那里也缺乏可靠性。) - Rick James
4
另外,TEXT无法有默认值,而VARCHAR可以。请参阅为什么MySQL中的文本列不能有默认值?- Stack Overflow - Peter V. Mørch
27
当您想创建包含两个最大长度字符串列的表格时,需要使用TEXT。这意味着这两列中的每一个都可以容纳65535个字符。您不能同时在一个行中使用两个具有最大长度的变长字符串(varchar),因为MySQL已经限制了最大行大小为65535。但是,您可以使用两个TEXT类型的列,因为TEXT只对行大小限制贡献了9到12个字节,而且TEXT的内容会单独存储,不会与行的其他部分混合存储。 - Searene
显示剩余13条评论

105
在上面的答案中,有一个重要的细节被省略了。
MySQL对每行最大大小施加了65535字节的限制。 VARCHAR列的大小计入最大行大小,而TEXT列被假定为通过引用存储其数据,因此只需要9-12字节。这意味着,即使您的VARCHAR字段的“理论”最大大小为65535个字符,如果您的表中有多个列,则无法实现该大小。
还要注意,VARCHAR字段所需的实际字节数取决于列的编码(和内容)。MySQL将使用向最大行大小使用的最大可能字节数进行计数,因此,如果您使用类似于utf8mb4几乎肯定应该使用)的多字节编码,它将使用更多的最大行大小。
更正:无论MySQL如何计算最大行大小,VARCHAR/TEXT字段数据是否实际存储在行中或通过引用存储取决于底层存储引擎。对于InnoDB,行格式影响此行为。(感谢Bill-Karwin)
使用TEXT的原因:
  • 如果您想存储一段以上的文本
  • 如果您不需要为该列建立索引
  • 如果您已经达到了表的行大小限制
使用VARCHAR的原因:
  • 如果您想存储几个单词或一个句子
  • 如果您想为(整个)列建立索引
  • 如果您想将该列与外键约束一起使用

3
不,VARCHAR和TEXT默认情况下都会将它们的一部分内容存储在行中。如果表的ROW_FORMAT=DYNAMIC 并且内容不适合行,则VARCHAR或TEXT都将存储为指向另一页的指针。 - Bill Karwin
10
有关 utf8mb4 占用更多字节的说法是不准确的。只有在您的内容需要多字节字符时,这些单个字符才会占据 2、3 或 4 个字节。utf8 中更常见的字符仍然每个字符占用 1 个字节。这就是 utf8 的整个意义! - Bill Karwin
2
同样在文档的同一页中,它说:“变长列的存储包括长度字节,这些字节计入行大小。例如,一个VARCHAR(255) CHARACTER SET utf8mb3列需要两个字节来存储值的长度,因此每个值最多可以占用767个字节。” 我并不是指utf8mb4总是使用4个字节,只是MySQL将其计算为最大行大小。 - Code Commander
2
我已经更新了我的答案,以澄清那些细节。现在看起来准确吗?@BillKarwin - Code Commander
3
没问题!+1。顺便说一下,MySQL中64KB限制和InnoDB行大小限制之间的奇怪差异是由于MySQL的存储引擎架构所致。当行从存储引擎传输到SQL层,然后变成结果集时,它们必须满足不同的规则。 - Bill Karwin
显示剩余6条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接