我在MySQL中有一个消息表,它记录用户之间的消息。除了典型的ID和消息类型(所有整数类型),我还需要将实际的消息文本保存为varchar或text。我将前端限制为3000个字符,这意味着消息插入数据库的时间永远不会超过这个长度。
使用varchar(3000)或text是否有理由?写varchar(3000)有点违反直觉。我已经阅读过其他类似的关于堆栈溢出的文章,但最好是获得特定于这种常见消息存储类型的视图。
- 有点老,但我来这里是因为我遇到了一个让我思考这个问题的问题。在我的例子中,我的前端表单被限制为2000个字符,但是我的存储方法中隐含的编码将国际字符编码为多个字符(每个字符可以有3到12个字符)。所以我的2000年突然变成了24000年。想些什么…
- 我发现对于许多并发插入来说,文本速度要快得多。
- @Jamess:utf8mb4…>
- 我投票决定关闭这个,因为它已经过时了。2010年晚些时候,新的行格式被引入,导致许多答案无效。这些答案被引用为福音书;与其留下错误的信息,不如去掉这条线索。
- 这里有一个新的线程:dba.stackexchange.com/questions/210408/…
- @里克·詹姆斯-你所涉及的问题根本不是同一个问题。请注意,此线程已被查看40000次,您建议用35个视图替换它,并将您自己的答案作为顶部答案?这个问题仍然是完全正确的,这里的答案是一个有用的记录。
- @里克詹姆斯考虑公布最新的答案,而不是结束问题。
- @我加了一个答案。我主要是想摆脱公认的答案,因为它已经过时了。我来问答是因为有人引用了错误的信息,说"754张赞成票,所以一定是对的"。好的,我也编辑了批准的答案。(尽管这感觉不合适。)
最新的VARCHAR或TEXT是存储内线,或Off-Records依赖于数据尺寸、Columns size、Row〔UFormat〕和MySQL版本。It does not depend on"text"vs"varchar."
- +1:varchar(内嵌存储)通常更快,如果经常检索数据(大多数查询都包括在内)。但是,对于通常不被检索到的大量数据(即,任何查询都不引用),最好不要将数据以内联方式存储。行大小有一个上限,用于内联存储的数据。
- 你能包括任何来源吗?你在哪里读的?谢谢。
- @跟踪狂2年后总是这样吗?我隐约记得我读到,如果文本很小的话,它们也可以是内联的。?
- @spencer7593,所以当我们在65535字节的行大小限制内时,应该是varchar还是text?当我们处于65535字节的限制范围内时,从表中存储数据究竟有什么好处?
- @pacerier:避免"内联"存储的确切好处是增加了可以存储在一个块中的行数,这意味着表行在innodb缓冲区缓存中占用的块更少(内存占用更少),意味着要传输到磁盘和从磁盘传输的块更少(I/O减少)。但是,如果存储的"行外"列在很大程度上没有被查询引用,那么这只是一个性能优势。如果大多数查询引用了这些"行外"列,那么这一好处将大大消失。如果列符合最大行大小并且经常被引用,则首选内联。
- @Spencer7593,这不是InnoDB特有的吗?Myisam呢?
- @Pacerier:我不认为这是InnoDB特有的。我相信这也适用于Myisam。我相信ndb引擎的不同之处在于,它以内联方式存储文本列的前255个字节;超过该字节的任何字节都存储在行外。pythian.com/blog/text-vs-varchar
- varchar以内联方式存储。从mysql manual dev.mysql.com/doc/refman/5.7/en/storage-requirements.html"可以存储在varchar或varbinary列中的有效最大字节数取决于最大行大小65535字节,这在所有列之间共享。"
- 有人能提供一些指针,告诉我们对于常见的硬件和数据场景,权衡可能在哪里?我知道我应该为我的特定案例做基准测试,但是如果我刚开始和/或没有时间运行广泛的基准测试,对于典型的场景,有哪些合理的拐点?
- "当大小合理时,varchar更快"。什么是"合理"的字符数,100?1000?100000?
- 对于InnoDB,此答案不正确。如果给定行上的值符合页面大小(16KB,并且每个页必须至少容纳两行),则varchar和blob/text都与其他列内联存储。如果字符串太大,则会溢出到其他页。有关详细说明,请参阅mysqlperformanceblog.com/2010/02/09/blob-storage-in-innodb。
- 但是,我同意这个回答中的一部分,即您应该使用数据、硬件和查询负载进行测试,因为这是唯一可以确定的方法。
- @ BillKarwin…如果我理解正确,那么在InnoDB上,对于小文本项,varchar和blob和text之间应该没有性能差异?那么,让每个varchar都成为text类型并让db管理内联与溢出是否明智呢?
- 文本或blob列的数据可能存储在两个单独的表中。文本或blob的前256个字节将存储在正在使用的表中。任何附加字节都存储在隐藏表中。隐藏表中的行的长度为2000字节。网址:http://dev.mysql.com/
- 如果一个select需要创建一个临时表,那么它总是在磁盘上创建,以防出现blob/text。对性能有很大影响
- 这个答案并不是绝对正确的,很明显,108位投票赞成@billkarwin的评论,承认答案不正确的人也应该在这里对答案投反对票。我们需要这些否决票来纠正这个制度。
- 这个答案是在引入row_format=dynamic和compressed之前写的。
- 有时候正确的答案会随着时间而改变。在理想情况下,不应将落选视为对曾经给出正确答案的人的批评,而应将新的正确答案视为"冒泡"以获得最多的选票。
- 然而,并不是每个人都能投反对票的人都能投反对票,所以总会出现不平衡。
你能预测用户输入要多久?
VARCHAR(X)
Case: user name, email, country, subject, password
文本BLCK1/中文文本
Case: large json bodies, short to medium length books, csv strings
朗特
Case: textbooks, programs, years of logs files, harry potter and the goblet of fire, scientific research logging
- 可预测性在这里真的是一个副作用。它实际上是最大预期长度,应该是决定因素。你提到的那些更容易预测的项目只是这样,因为它们比其他项目短。
- @安德鲁·巴伯,这就是我的观点。所有其他的帖子都很好地解释了两者之间的区别,但并没有解释在实际情况下你必须在两者之间做出选择。我试图指出使用varchar作为可预见的短文本是一个不错的选择,而使用文本作为任意长文本是一个不错的选择。
- 如果所有列都短且可预测(例如:MAC地址、IMEI等)是那些永远不会改变的东西)然后使用char列,你可以使你的行大小固定,如果使用myisam的话,这会大大加快速度,也可能是innodb,尽管我不确定。
- @matt aws rds基本上告诉你"使用innodb或者你的备份很有可能是$%*ed。"mysql几乎是innodb有全文搜索的版本,myisam将几乎完全过时。
- @michaelj.calkins在mysql 5.6中发生的事情。现在您还可以在InnoDB中进行全文搜索。参见dev.mysql.com/doc/refman/5.6/en/fulltext-search.html
- @Phoneix不知道是哪个版本做的!我现在很兴奋:)
- 字符限制:tinytext:255;文本:65535;中文本:16777215;长文本:4294967,29。
- @胜利者标准——这些是byte限制,而不是character限制。另请参见stackoverflow.com/questions/13932750/…
- @马特-"固定"在Myisam中可能会更快,也可能不会更快。对于InnoDB,它什么也不买。
Just to clarify the best practice:
Text format messages should almost be stored as text(they end up being arbitrarily long)
字符串属性应保持为Varchar(目的地名称、主体等)。
我知道你有一个前端极限,这是伟大的,直到它没有。"Grin&35;42;the trick is to think of the DB as separate from the applications that connect to i t.由于一个应用程序在数据上设定了一个极限,所以并不意味着数据本身是有限的。
他们的信息是什么,他们的力量从未超过3000个字符?如果这只是一个仲裁应用限制(例如,对于一个文本框或某种东西),则在数据层中使用TEXT字段。
- "哪一个最好,直到它不是"是什么意思?"不是"指什么?
- @Pacerier给你举了一个"不是"的例子,James可能会说:以Twitter为例,他直到最近对PMS有140个字符的限制。他们认为这不再明智,并选择完全取消这一限制。如果他们不提前考虑这个问题(我很肯定他们可能会这样做…),他们就会进入上面概述的场景。
- 我只是在建立我们的新数据库,我想没人能在我们的小评论框里放超过2000个字符,然后,正如詹姆斯所说,今晚突然"不好",因为一个用户输入了2600个字符的非常有效的评论。我用了varchar(2000年),认为它不可能比这长,我错了。所以是的,它是伟大的,直到它不是。在我们的情况下,只花了几天就显出来。下面的规则,迈克尔·J·卡尔金斯,我想从现在开始我会用的。消息、评论的文本。
- @Pacerier"在它不伟大之前是伟大的"。换句话说,它几乎一直都在工作,而且非常棒……除了那些不太好的特殊情况。
- @Pacerier在所选答案的评论中提到了另一个有趣的例子,基本上他有2000个字符的前端限制,但所引入的字符是在一个代码页中,实际使用的字节比普通字母多,他的数据库最终需要24K个字符的空间,因为他必须考虑到所引入字符的字节大小。
我不是一个神秘的专家但这是我对问题的理解。
我认为文字是在神秘之路之外保存的,而我认为瓦尔查是保留在神秘之路的一部分。我的路有一个最大的长度。所以你可以限制你用Varchar存储的其他数据。
另一个原因是Varchar形成了街道的一部分,我怀疑在那一片土地上,所看到的东西会比用一篇恰克文章的东西慢得多。
- 行长度限制为65535字节[dev.mysql.com/doc/refman/5.0/en/column-count-limit.html]。如果您的列是utf8编码的,这意味着3000个字符的varchar列最多可以占用9000个字节。
- UTF-8字符最多可以是4个字节,所以我认为您的意思是12000个字节(除非这里有一些我不理解的MySQL)。
- @raylu mysql的utf-8是"假utf-8",因为它最多只支持每个字符3个字节,所以无法在mysql的utf-8中直接存储BMP平面以外的Unicode字符。这在MySQL5.5中是固定的。
- 我相信这个断言只对Myisam有效。我找不到确切的来源,但我相信InnoDB也在表中内联存储了TEXT。
- @Dotanchohen我在这里找到了一个解释,使用innodb存储可变长度数据可能会有所不同(可以在外部或行内存储)mysqlserverteam.com/external-stored-fields-in-innodb
- @基索蒂兰:很好,谢谢你!
- MySQL5.1使用3字节的UTF-8。mysql 5.5及更高版本使用4字节的utf-8(utf8mb4)。
- 根据行格式、行大小和其他内容,TEXT或varchar中的任何一个、部分或全部都将存储在记录之外。您不能简单地说明在InnoDB中所做的工作。
- @AnthonyRutledge-5.1没有utf8mb4;5.5-5.7有utf8mb4选项;8.0默认为完整的4字节utf-8。
- @是的,但是它有一个三字节的UTF-8。
- @是的,EDOCX1(最大3字节)从4.1开始就出现了。
- @不过,Rickjames对游标、视图、触发器和存储过程感到羞愧。
短期答案:没有实用、性能、存储、差异。
Long answer:
VARCHAR(3000)和TEXT之间根本没有区别。The former will trancate at 3000 characters;the latter will trancate at 65535 bytes.(我区分字节和字符,因为一个字符可以使用多个字节。)
在VARCHAR中,在TEXT上有一些优势。
- "Smaller"means 191,255,512,767,or 3072,etc,depending on version,context,and CHARACTER SET.
- 在如何指数大的柱上是有限的。(767 or 3072 bytes;this is version and settings dependent)
- 中间表由复杂的SELECTs创建,以两种不同的方式处理——记忆(快速)或弥伊桑(慢)。当大型柱被卷入时,速度慢的技术自动地被捕捉。(Significant changes coming in Version 8.0;so this bullet item is subject to change.)
- 与前一个项目有关的所有数据类型(与VARCHAR对比)这是自动化的worse for generated temp tables than the VARCHAR。(但这是第三个方向的讨论!)
- 像埃多克斯1,2,1,1,1,1,1,1,1,1,3
反复回答其他问题
原始问题提出了一个问题(数据类型要使用);被接受的答案是一些(Off-Record Storage)。答案现在已经不在日期了。
当这一威胁开始并得到答复时,无害环境技术中只有两种"滚动格式"。引进了两种以上的格式(EDOCX1&22)和EDOCX1&23)。
存储位置为TEXT和VARCHAR()是基于大小而不是数据类型的名称。For an updated discussion of on/off-record storage of large text/blob columns,see this.
前面的答案对主要问题没有足够的坚持:即使在非常简单的查询中,比如
可以需要一个临时表,如果涉及到一个VARCHAR字段,它将在临时表中转换为一个CHAR字段。因此,如果您的表中有50万行带有一个VARCHAR(65000)字段,那么仅此列就将使用6.5*5*10^9字节。这样的临时表不能在内存中处理,而是被写入磁盘。预计影响将是灾难性的。
来源(带指标):https://nicj.net/mysql-text-vs-varchar-performance/(这是指在"标准"(?)中处理TEXT与VARCHAR。Myisam存储引擎。其他方面可能不同,例如InnoDB。)
- InnoDB:5.7版也一样。对于8.0,varchar temps是可变长度的。
varchar用于电子邮件地址等小数据,而文本用于新闻文章等大数据,blob用于图像等二进制数据。
varchar的性能更强大,因为它完全是从内存中运行的,但是如果数据太大,例如varchar(4000),就不会出现这种情况。
另一方面,文本不会粘附在内存中,并且会受到磁盘性能的影响,但是可以通过在单独的表中分离文本数据并应用左联接查询来检索文本数据来避免这种情况。
blob的速度要慢得多,所以只有当您没有像10000个图像这样的数据时才使用它,这将花费10000条记录。
请遵循以下提示以获得最大速度和性能:
将varchar用于名称、标题、电子邮件
对大数据使用文本
在不同的表中分隔文本
对ID(如电话号码)使用左联接查询
如果要使用blob,请应用与文本中相同的提示
这将使查询在数据大于10 m且保证大小高达10GB的表上花费毫秒的时间。