为什么不使用varchar(max)?


76

关于数据库设计,我有点老了,所以我完全赞成在列中使用正确的数据大小。但是,在查看一个朋友的数据库时,我注意到他使用varchar(max)了很多东西。现在,我立即想到的是将其退还给他,并告诉他进行更改。但是后来我考虑了一下,不能为他不使用它提供充分的理由(如果您想知道的话,他曾使用过一个案例类型工具来生成数据库)。

我一直在研究varchar(max)用法的主题,但我不能提出任何不使用它的充分理由。

他不使用列作为索引,位于数据库上的应用程序对输入有限制,因此不允许在字段中输入大量条目。

任何帮助将不胜感激,以帮助我让他看到光:)。


1
看到这个答案的另一个原因stackoverflow.com/questions/2009694/...
马丁·史密斯

那很有意思!可惜我没早发现这个。谢谢!
2011年

5
例如:您不能在列上放置索引VARCHAR(MAX)...仅凭它使我仅在绝对需要时才使用它。–
marc_s

1
我会指出,期望应用程序始终控制输入是愚蠢的。数据几乎将超出应用程序的使用寿命,并且下一版本的应用程序可能没有正确的限制。
HLGEM 2014年

Answers:


35

我对此的回答与Max的用法无关,而与VARCHAR(max)vs TEXT的原因有关。

在我的书中;首先,除非您可以绝对确定除了英语文本之外,否则您都不会编码任何东西,而且人们不会引用异国名称,那么您应该使用NVARCHAR或NTEXT。

其次,这是字段允许您执行的操作。

与VARCHAR相比,TEXT很难更新,但是您可以利用全文索引和许多巧妙的功能。

另一方面,VARCHAR(MAX)有一些歧义,如果单元格的大小小于8000个字符,它将被视为行数据。如果更大,则出于存储目的,它将被视为LOB。由于不查询RBAR就无法知道这一点,因此对于需要确定数据及其读取成本的地方,这可能具有优化策略。

否则,如果您的使用情况相对平凡,并且您不希望数据大小出现问题(即,您使用的是.Net,因此不必担心字符串/字符*对象的大小)然后使用VARCHAR(max)就可以了。


4
我在阅读有关它的文章时注意到的一件事是,当您查询一个表时,它必须在内存中缓冲记录的最大大小。因此这可能是个问题,但是在当今具有多个演出(如果不是TB级)且ram便宜且易于升级的环境中,这个问题几乎没有解决。
2011年

14
这个答案似乎暗示全文索引只能与text数据类型一起使用。不是这种情况。text是已弃用的数据类型,与varchar(max)AFAIK相比没有优势。
马丁·史密斯

7
不使用TEXT / NTEXT的另一个原因是不建议使用它们。
亚伦·贝特朗

1
你能引用吗?我只知道TEXT IN ROW已弃用。
拉斯克拉克

1
MSSQL联机丛书在将来的Microsoft SQL Server版本中,将删除ntext,text和image数据类型。避免在新的开发工作中使用这些数据类型,并计划修改当前使用它们的应用程序。请改用nvarchar(max),varchar(max)和varbinary(max)。
tibx

12

有一篇博客文章关于为什么不在这里使用varchar max

编辑

基本区别在于数据的存储位置。SQL数据行的最大大小为8000个字节(或者为8K)。这样就无法将2GB的varchar(max)存储在数据行中。SQL Server将其存储为“行外”。

因此,由于数据将不在磁盘上的同一位置,因此可能会导致性能下降,请参阅:http : //msdn.microsoft.com/zh-cn/library/ms189087.aspx


1
是的,我读过,但仍然让我有疑问。如果代码编码正确,从而限制了应用程序中的数据,那么它就不会降低性能。索引编制不是问题,最后一点是关于设计的,我的朋友并不关心。
AtaLoss,2011年

1
除非行中存储的数据超出行限制(是的,大约为8k),否则varchar(max)不会存储在行外。即,如果将文本“ hello world”存储在具有3列的表的varchar max中,则很可能不会将其存储在行外。
2011年

不使用它们的原因是它们无法被索引。如果您希望有需要的数据使用nvarchar(max)或varchar(max),那么这是一个不好的做法。
HLGEM 2014年

它并不总是对性能造成影响。如果行大小减小,表扫描将加快速度。如果所讨论的varchar(max)很少在查询中使用,将其移出行将提高性能。
johnnycrash

2
当您无法预期可能需要插入到行中的字符串的大小时,性能上的提高值得您进行操作上的正确性。
宾基

2

如果您在OLTP环境中工作,那么一切都与性能有关。从开销和调整问题到索引限制和查询瓶颈。使用varcahr(max)或任何其他LOB类型很可能会违反大多数设计最佳实践,因此,除非存在无法通过使用某些其他类型输入机制来处理的特定业务需求,并且只有varchar(max)才适合那么,为什么要使您的系统和应用程序遭受一种LOB数据类型固有的开销和性能问题呢?

另一方面,如果您是在OLAP环境中或在带有维表的维表的Star Schema DW环境中工作,而这些表的字段自然需要冗长,那么只要不将其添加到索引中,就可以使用varchar(max),可能有用。即便如此,我仍建议使用char(x)varchar(x),因为仅使用那些绝对是完成工作所必须的资源始终是最佳实践。


1

除非您期望有大量数据,否则不应该使用它们,这是其原因(直接从在线图书获得):

大对象(LOB)数据类型为ntext,text,varchar(max),nvarchar(max),varbinary(max),xml或image的列不能指定为索引的键列。

如果要降低性能,请对所有内容使用nvarchar。


2
但是,如果您从不首先在该列上键入该怎么办?如果要存储一小段文本,则可能是通过其他键列查找它。需要将索引放在可能会存储自由格式的文本并且WHERE除非进行检查就永远不会出现的列上,这是什么大问题IS NULL
宾基

@binki,建议不要对所有内容都使用varchar(max),因为会有一些字段需要索引。仅适用于需要大量数据的情况。
HLGEM '16

1
仅仅因为它来自在线书并不意味着它是正确的:)有时正确使用(MAX)的另一个例子是,当您存储源中未定大小的字符串(例如,blob,NOSQL字段)时,您不会不知道它可能有多大。我同意@binki的说法,经常有几列您永远都不会索引。
6

1

Redgate撰写了一篇很棒的文章。
https://www.red-gate.com/simple-talk/sql/database-administration/whats-the-point-of-using-varcharn-anymore/

结论

  • 在适当的情况下,出于良好设计的目的(如果不带来性能优势),并且因为VARCHAR(MAX)数据不会压缩,请使用VARCHAR(n)而不是VARCHAR(MAX)
  • 存储大字符串比存储小字符串需要更长的时间。
  • 将行内VARCHAR(MAX)值从8,000以下更新到8,000以上相对较慢,但单笔交易的差异可能无法测量。
  • 与将表设置为存储行外数据相比,将行内VARCHAR(MAX)值从8,000更新到8,000以下更快。
  • 对VARCHAR(MAX)使用行外选项将导致写入速度变慢,直到字符串很长为止。

0

从性能,内存和存储的角度来看,我不知道sql server如何处理大(声明的)varchar字段。但是假设这样做与较小的声明的varchar字段一样有效,那么完整性约束仍然有好处。

位于db上的应用程序应该具有输入限制,但是如果应用程序在这方面有错误,则数据库可以正确地报告错误。


这是一个好方法,特别是如果您不使用托管语言来读取字符串。
Russ Clarke

这是一个好点。我会提到这一点,它是用c#3.5或4开发的(我相信,我应该问他)。
2011年


@RussClarke可变长度字符串真的是只托管的东西吗?听起来您从未在非托管环境中遇到堆分配:-p。
宾基

@MartinSmith这些是非常小的性能改进。另外,博客作者VARCHAR(MAX)WHERE子句中使用了比较。我期望的用例VARCHAR(MAX)是您无法比较的或WHERE用SQL编写的用例,例如,博客文章内容blob,某物的自由格式文本描述。如果您想比较或WHERE,那么约束当然会有所帮助。他的例子'abc'甚至可以翻译成两个整数的比较。那不是那种放在VARCHAR(MAX)……中的数据
。– binki

0

差异位于下一个:
VARCHAR(X)可以被索引并存储在MDF/NDF数据文件中。
VARCHAR(MAX)无法索引,因为可以达到高容量,然后将其存储为单独的文件,而不是存储在MDF/NDF数据文件中。


6
您是否认为MS SQL将LOB数据存储在哪里(如果不在.mdf文件中)?

0

   认为应用程序只会将短字符串传递给数据库,这有点过时,这将使它正常

   在近代,你HAVE预测数据库将由目前的应用主要是访问,但也有可能是应用程序的未来版本,(将那个版本知道的开发商保持一定的长度低于字符串?)

   您必须预期Web服务,ETL流程,从LYNC到SQL以及任何其他数量的现有技术和/或尚不存在的技术都将用于访问数据库。

   一般来说,我尽量不要使用varchar(4000),因为毕竟它是4000个字符。如果超出该范围,那么我将寻找其他数据类型来存储要存储的内容。 布伦特·奥扎尔(Brent Ozar)为此写了一些很棒的文章。

   综上所述,在进行项目时,评估当前设计对当前需求的方法很重要。了解各个部分的工作方式,了解各种方法的权衡并解决当前的问题。行使一些伟大的公理会导致盲目遵守,这可能会使您陷入困境

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.