varchar(max)随处可见?


80

使您的所有Sql Server 2008字符串列都为varchar(max)有任何问题吗?我允许的字符串大小由应用程序管理。该数据库应仅保留我提供的内容。通过将所有字符串列声明为SqlServer 2008中的varchar(max)类型,无论实际输入到它们中的数据大小如何,都会对性能产生影响吗?


1
在我的阅读中,这听起来像Sql Server varchar列本身“自动调整大小”。那么,任何给定值的最大长度为20的varchar(max)列与varchar(20)列相同吗?
BowserKingKoopa 2010年

Answers:


48

通过使用该方法,VARCHAR(MAX)您基本上是在告诉SQL Server“将值存储在此字段中的方式看起来最好”,然后SQL Server将选择是将值存储为常规值VARCHAR还是LOB(大对象)。通常,如果存储的值小于8,000字节,SQL Server会将值视为常规VARCHAR类型。

如果存储的值过大,则列被获准在LOB页洒掉的页面,正是因为他们对其他LOB类型做(textntextimage) -如果发生这种情况,然后附加页读取需要读取存储在数据额外的页面(即性能低下),但这仅在存储的值太大时才会发生

实际上,在SQL Server 2008或更高版本下,即使使用固定长度的数据类型(例如VARCHAR(3,000)),数据也可能溢出到其他页面上,但是这些页面称为行溢出数据页面,并且处理方式略有不同。

简短版:从存储角度看,使用VARCHAR(MAX)over VARCHAR(N)for some没有缺点N

(请注意,这也适用于其他可变长度字段类型NVARCHARVARBINARY

仅供参考-您不能在VARCHAR(MAX)列上创建索引


这仅对可为空的字段适用。每个非空varchar(max)或nvarchar(max)列都需要24个字节的附加固定分配。 docs.microsoft.com/en-us/sql/t-sql/data-types/…–
Liazy

33

索引的宽度不能超过900个字节。因此,您可能永远无法创建索引。如果您的数据少于900字节,请使用varchar(900)。

这是一个缺点:因为它给

  • 搜索效果真的很差
  • 没有独特的约束

但是,如果varchar(max)列没有大于900字节的任何值怎么办?那会索引吗?我很困惑,因为我正在阅读的许多内容使varchar列类型听起来像它们在输入数据时自动将自身大小调整为最大值。这对于我想要的东西将是完美的,因为应该由应用程序来决定最大值,而不是数据库。
BowserKingKoopa

3
创建索引时会出现警告,而尝试插入> 900时会出现错误。但是,如果数据始终小于900,为什么不使用900?是的,尽管它们存储为可变长度字符串。
gbn 2010年

8
我不知道我的数据是否总是<900。这是业务逻辑问题。如果该规则发生更改,我应该在业务逻辑中进行更改。我也不必更改数据库。无论如何,这就是我的目标。看看我是否可以摆脱对字符串大小的担忧,而又不会明显降低性能。
BowserKingKoopa

2
索引长文本列多久有用一次?甚至值得为诸如varchar(200)列之类的索引编制索引吗?毕竟,索引本身效率很低。似乎不太可能需要搜索长时间的“完全匹配”。而且只有在知道模式的开始的情况下,模式搜索才会受益。
2014年

9

Simon Sabin在这段时间写了一篇文章。我现在没有时间抓住它,但是您应该搜索它,因为他得出的结论是,默认情况下您不应该使用varchar(max)。

编辑:西蒙有一些关于varchar(max)的帖子。下面评论中的链接很好地显示了这一点。我认为最重要的是http://sqlblogcasts.com/blogs/simons/archive/2009/07/11/String-concatenation-with-max-types-stops-plan-caching.aspx,它讨论了效果计划缓存中的varchar(max)的大小。一般原则是要小心。如果您不需要最大字符数,那么就不要使用max-如果您需要超过8000个字符,那么请确保...。




第一个。由OMG Ponies。
罗伯·法利

抱歉,我没有时间找到实际的链接,当我想提出答案时,我正准备参加会议。
罗伯·法利


6

对于这个问题,我没有提到一些要点。

  1. 在2005/2008/2008 R2上,如果索引中包含LOB列,则将阻止联机索引重建。
  2. 在2012年,取消了联机索引重建的限制,但LOB列无法参与新功能“将NOT NULL列添加为联机操作”
  3. 可以在包含此数据类型列的行上更长时间地取出锁。(更多

我的答案还包括其他一些原因,说明为什么没有varchar(8000)到处都是

  1. 您的查询最终可能会请求大量的内存授予,而这些授予不能由数据大小来证明。
  2. 在带有触发器的表上,它可能会阻止不添加版本标记的优化。

5

我之前也问过类似的问题。得到了一些有趣的回复。看看这里 在一个站点上,有一个人在谈论使用宽列的危害,但是,如果您的数据在应用程序中受到限制,我的测试将证明这一点。您无法在列上创建索引的事实意味着我不会一直使用它们(就我个人而言,我根本不会使用它们太多,但是在这方面我有点纯粹主义者)。但是,如果您知道其中没有太多存储,我认为它们没有那么糟糕。如果对其中具有varchar(max)的记录集的列(或任何宽列为char或varchar)进行任何排序,则可能会遭受性能损失。这些可以通过索引来解决(如果需要),但是不能将索引放在varchar(max)上。如果您想将来验证您的色谱柱,为什么不将它们放在合理的位置。例如,名称列为255个字符,而不是最多...


2

还有另一个原因要避免在所有列上使用varchar(max)。出于相同的原因,我们使用检查约束(以避免用错误的软件或用户输入引起的垃圾填入表),因此,我们希望防止出现任何错误的过程,该过程会添加比预期更多的数据。例如,如果某人或某物试图向City字段中添加3,000个字节,我们可以肯定地知道某物不对劲,并希望停止进程停滞不前,以便尽早对其进行调试。我们还将知道,一个3000字节的城市名称可能无效,并且会弄乱报告,如果我们尝试使用它的话。


1

理想情况下,您应该只允许您需要的东西。这意味着如果您确定某个特定列(例如,用户名列)的长度永远不会超过20个字符,那么使用VARCHAR(20)与VARCHAR(MAX)可以使数据库优化查询和数据结构。

从MSDN:http : //msdn.microsoft.com/en-us/library/ms176089.aspx

Variable-length, non-Unicode character data. n can be a value from 1 through 8,000. max indicates that the maximum storage size is 2^31-1 bytes.

对于这些列,您真的要接近2 ^ 31-1个字节吗?


3
我认为将其描述为“分配”是不正确的。数据库当然不会在任何地方保留2 ^ 31-1个字节。
斯科特·斯塔福德,

1
“用户名列[..]的长度永远不会超过20个字符”-很好,直到有一天客户决定需要更长的时间。我们都去过那里。:)
史蒂夫·史密斯,
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.