varchar(500)比varchar(8000)更有优势吗?

jco*_*lum 89 sql t-sql sql-server

我已经在MSDN论坛和这里读到了这个,我还不清楚.我认为这是正确的:Varchar(max)将存储为文本数据类型,因此存在缺陷.因此,假设您的字段可靠地低于8000个字符.像我的数据库表中的BusinessName字段.实际上,商业名称可能总是在(从我的帽子里拿出一个数字)500个字符.看起来我运行的大量varchar字段远低于8k字符数.

那么我应该将该字段设为varchar(500)而不是varchar(8000)吗?根据我对SQL的理解,这两者之间没有区别.因此,为了简化生活,我想将所有varchar字段定义为varchar(8000).这有什么缺点吗?

相关:varchar列的大小(我不觉得这个回答了我的问题).

Mar*_*ith 122

这可以产生影响的一个示例是,它可以阻止性能优化,避免将行版本控制信息添加到具有after触发器的表中.

SQL Kiwi在此处对此进行了介绍

存储的数据的实际大小并不重要 - 重要的是潜在的大小.

类似地,如果自2016年以来使用内存优化表,则可以使用LOB列或列宽的组合,这些列可能会超出inrow限制但会有惩罚.

(Max)列始终存储在行外.对于其他列,如果表定义中的数据行大小超过8,060字节,则SQL Server会将最大的可变长度列推送到行外.同样,它不依赖于您存储在那里的数据量.

这会对内存消耗和性能产生很大的负面影响

过度声明列宽可以产生很大差异的另一种情况是,是否将使用SSIS处理表.为可变长度(非BLOB)列分配的内存对于执行树中的每一行是固定的,并且是根据列声明的最大长度,这可能导致内存缓冲区的低效使用(示例).虽然SSIS包开发人员可以声明比源更小的列大小,但这种分析最好先预先完成并在那里强制执行.

回到SQL Server引擎本身,类似的情况是,在计算为SORT操作分配的内存授权时,SQL Server假定varchar(x)列平均消耗x/2字节.

如果您的大多数varchar列都比这更完整,这可能会导致sort操作溢出tempdb.

在你的情况下,如果你的varchar列被声明为8000字节,但实际上内容远远少于你的查询将被分配它不需要的内存,这显然是低效的,并可能导致等待内存授予.

这可以在SQL Workshops Webcast 1的第2部分中讨论,可从此处下载或参见下文.

use tempdb;

CREATE TABLE T(
id INT IDENTITY(1,1) PRIMARY KEY,
number int,
name8000 VARCHAR(8000),
name500 VARCHAR(500))

INSERT INTO  T 
(number,name8000,name500)
SELECT number, name, name /*<--Same contents in both cols*/
FROM master..spt_values

SELECT id,name500
FROM T
ORDER BY number
Run Code Online (Sandbox Code Playgroud)

截图

SELECT id,name8000
FROM T
ORDER BY number
Run Code Online (Sandbox Code Playgroud)

截图

  • @AlexKuznetsov - 对于那种情况,我会将它们声明为`char(4)`,因为每个变量列有2个字节的开销. (12认同)

BBl*_*ake 18

从处理的角度来看,使用varchar(8000)和varchar(500)并没有什么区别.定义字段应该保持的最大长度并使varchar成为一个长度,这更像是一种"良好实践".它可用于协助数据验证.例如,将州名缩写为2个字符或邮政/邮政编码为5或9个字符.当您的数据与字段长度至关重要的其他系统或用户界面(例如,大型机平面文件数据集)进行交互时,这曾经是一个更重要的区别,但现在我认为它比其他任何东西更习惯.

  • 对于自然拥有最大长度的东西有意义.但是当最大长度不明显时你会怎么做?例如商业名称. (3认同)
  • 即使在2017年,这似乎也会对性能产生影响:http://dba.stackexchange.com/a/162117/1822 (3认同)
  • 对于类似的东西,如果我没有预见到任何方式来预测大小可能是什么,那么我通常会使用varchar(8000)或varchar(max),具体取决于数据类型 (2认同)
  • 最近的答案表明存在 * 成本:它影响优化逻辑 [Martin Smith 的回答](http://stackoverflow.com/a/5654947/199364) 并且还考虑了 [gbn] 提到的 8K 总行大小问题(http ://stackoverflow.com/a/2009789/199364) 和 [Oliver](http://stackoverflow.com/a/20700888/199364)。 (2认同)

gbn*_*gbn 9

除了最佳实践(BBlake的答案)

  • 使用DDL会收到有关最大行大小(8060)字节和索引宽度(900字节)的警告
  • 如果超过这些限制,DML将会死亡
  • ANSI PADDING ON是默认值,因此您最终可能会存储一整行空白

  • 只是为了澄清ANSI PADDING ON:当使用`nvarchar`和`varchar`类型时,这只意味着在插入时保留尾随空格 - 而不是用空格填充值到列的大小,如`char `和`nchar`. (37认同)

Oli*_*ver 9

对于不太明显的大型列而言,存在一些缺点,可能会稍后发现:

  • 您在INDEX中使用的所有列不得超过900个字节
  • ORDER BY子句中的所有列不得超过8060个字节.这有点难以掌握,因为这仅适用于某些列.有关详细信息,请参阅SQL 2008 R2超出行大小限制)
  • 如果总行大小超过8060字节,则会出现该行的" 页面溢出 ".这可能会影响性能(一个页面是SQLServer中的一个分配单元,固定为8000字节+一些开销.超过这个不会很严重,但它是显而易见的,你应该尽量避免它,如果你很容易就可以)
  • 许多其他内部数据结构,缓冲区和最后 - 至少您自己的变量和表变量都需要镜像这些大小.如果大小过大,过多的内存分配会影响性能

作为一般规则,尽量保持列宽.如果它成为问题,您可以轻松扩展它以满足需求.如果您稍后发现内存问题,稍后缩小宽列可能会变得不可能而不会丢失数据,您将不知道从哪里开始.

在您的商家名称示例中,请考虑显示它们的位置.真的有500个字符的空间吗?如果没有,那么存储它们就没有什么意义了.http://en.wikipedia.org/wiki/List_of_companies_of_the_United_States列出了一些公司名称,最大值约为50个字符.所以我最多使用100作为列.也许更像80.