使用MAX文字或更具体的小字体


22

有人正在查看我的DDL代码以创建表,并提出了建议,当他们看到我看到使用VARCHAR(256)文本字段时,我希望它很小,例如名字或其他名称,我应该始终使用VARCHAR(MAX)并链接为什么使用varchar(max )。我读了它,但它似乎过时了,因为它专注于2005年,并且似乎没有提供任何真正的理由在所有文本字段上每行可能分配多达2 GB的空间。

从性能,存储等方面来看,应该如何决定是否VARCHAR(MAX)对现代版本的SQL Server 使用或更小的更具体的类型?(例如,2008、2012、2014)

Answers:


31

我应该一直使用(n)varchar(max)文本列吗?

没有。

对于SQL Server,max仅应在没有其他选择时指定数据类型。而是应该选择正确的基本类型(varcharnvarchar),并指定适合存储数据的明确的最大长度。

无论列的键入为varchar(n)还是varchar(max),物理存储都是相同的,因此不必担心。

选择(n)varchar(max)任何地方的原因都围绕功能,计划质量和性能。

详尽的列表可能不切实际,但除其他外,max列:

特征

  • 需要单独的约束以强制最大长度
  • 不能是索引中的键(因此也没有唯一约束)
  • 可能会阻止在线DDL(包括索引重建和添加新的非null列)
  • 通常不支持“较新”功能,例如列存储
  • 有关更多特定功能和限制,请参阅产品文档。通常的模式是在max数据类型上有一些笨拙的限制。并非所有限制和副作用都记录在案。

性能

  • 需要执行引擎中的特殊处理,以解决可能非常大的问题。通常,这涉及使用效率较低的代码路径以及流接口
  • 可能会对外部代码(和其他SQL Server组件,如SSIS)产生类似的意外后果,还必须准备处理最大2GB的数据
  • 在内存授权计算中假定为4000字节宽。这很可能导致过多的内存保留,这限制了并发性,并将有价值的索引和数据页从缓存中推出
  • 禁用一些重要的性能优化
  • 可能会延长锁定时间
  • 可能会阻止优化器选择(非动态)搜索计划
  • 防止过滤器进入扫描并寻找残留物
  • 可能会增加tempdb压力和争用(取决于版本),因为变量和参数也可能被键入max以匹配列定义

总之,不必要地使用说明max符会产生许多微妙的(和不良的)副作用,因此这样做是没有意义的。使用单个声明的次要“便利”是没有任何补偿的。

在上下文中评估每种类型,使用正确的基本类型(varcharnvarchar)和合理的显式长度。

进一步阅读:


8

这看起来像是一个偏执狂的答案,但不仅是存储和性能方面的考虑。

数据库本身不控制其客户端,并且不能假定客户端始终安全地插入用户输入-即使数据库被设计为仅与使用Entity Framework封装事务并确保参数化查询的.net应用程序一起使用被系统地使用,您不知道会一直如此。

我不知道确切如何执行此操作,但是通过设置所有文本字段varchar(max),如果客户端遇到Bobby Tables问题和/或您的存储过程的参数也为varchar(max),则可以使攻击者更容易提出问题一个有效但巧妙的邪恶参数值,可以执行客户端不应该执行的操作-无论执行什么操作。

通过限制长度,你真正需要的,你没有屏蔽从这些聪明的攻击自己(我甚至不知道它实际上是所谓的,我只记得阅读关于它而回),但你不能说“继续,尝试给我一个2GB的脚本来运行”。


所谓的可能是“注入”(更具体地讲是“ SQL注入”)。
Andriy M

@AndriyM是的,出于某种原因,我在考虑SQL截断攻击(MS似乎删除了我添加了书签的链接),但这基本上是在利用varchar(not-max)参数,因此我在这里有些mouth脚。但是,是的,SQL注入将在此处适用。也许我应该改一下这个答案。
Mathieu Guindon
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.