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


90

我已经在MSDN论坛上对此进行了阅读,但我仍然不清楚。我认为这是正确的:Varchar(max)将存储为文本数据类型,因此存在缺点。因此,可以说您的字段可靠地在8000个字符以内。就像数据库表中的BusinessName字段一样。实际上,公司名称可能总是少于500个字符(将数字输入我的帽子)。在8k字符数以下,我遇到的许多varchar字段似乎都很好。

那么我应该将该字段设置为varchar(500)而不是varchar(8000)吗?从我对SQL的了解来看,两者之间没有区别。因此,为了使生活更轻松,我想将所有varchar字段都定义为varchar(8000)。那有什么缺点吗?

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


6
想象一下试图在名片上使用500个字符长的公司名称... :)
OMG Ponies 2010年

2
@OMG小马:每当我看到您的用户名时,我都会笑。现在,你在说什么?(开个玩笑)
jcollum

4
@jcollum:SpaceMan Spiff将永远获得我的投票。这是不正确的- 任何卡尔文与霍布斯会做,特别是雪雕刻的。或霸王龙驾驶F-14。但我离题了……
OMG Ponies 2010年

Answers:


20

从处理的角度来看,使用varchar(8000)与varchar(500)不会有什么区别。定义字段应保留的最大长度并将varchar设置为该长度,这更像是一种“最佳实践”。它可以用来协助数据验证。例如,将州名缩写设置为2个字符,或将邮政编码输入5个或9个字符。在您的数据与其他对字段长度至关重要的系统或用户界面(例如,大型机平面文件数据集)进行交互时,这曾经是一个更为重要的区别,但如今,我认为它比其他任何东西都更为习惯。


3
有道理...对于自然具有最大长度的事物。但是当最大长度不明显时该怎么办?例如公司名称。
jcollum 2010年

2
对于这样的事情,如果我没有预见到任何预测大小可能的方法,那么我通常会使用varchar(8000)或varchar(max),具体取决于数据类型
BBlake

4
即使在2017年,这似乎也确实在性能上有所不同:dba.stackexchange.com/a/162117/1822
a_horse_with_no_name

1
最近的答案表明,这是有代价的:它影响了优化逻辑Martin Smith的答案,还考虑了gbnOliver提到的8K总行大小问题。
ToolmakerSteve

124

一个可以有所作为的示例是,它可以防止性能优化,该性能优化避免使用后触发将行版本控制信息添加到表中。

这在此处由SQL Kiwi涵盖

所存储数据的实际大小无关紧要-潜在的大小至关重要。

同样,如果自2016年以来使用内存优化表,则有可能使用LOB列或列宽度的组合,这些组合可能会超出行数限制,但要付出代价。

(Max)列始终存储在行外。对于其他列,如果表定义中的数据行大小可以超过8,060字节,则SQL Server会将最大的可变长度列下推。同样,它不取决于您存储在此处的数据量。

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

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

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

如果您的大多数varchar专栏文章都比这多,那可能会导致sort操作溢出到tempdb

就您而言 varchar列被声明为8000字节,但是实际上所包含的内容远远少于查询所分配的内容,那么它不需要的内存显然是效率低下的,并且可能导致等待内存授予。

SQL Workshops网络广播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

屏幕截图

SELECT id,name8000
FROM T
ORDER BY number

屏幕截图


1
因此,如果我几乎所有的值都是3或4个字符,并且曾经不能超过4个字符,并且我想避免“排序操作溢出到tempdb”,我将声明我的列VARCHAR(8)并使用CHECK约束来强制执行该列宽度不能超过4个字符。你怎么看?
AK 2012年

12
@AlexKuznetsov-在这种情况下,我将其声明为char(4)每变量列有2个字节的开销。
马丁·史密斯

9

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

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

38
只是为了阐明ANSI PADDING ON:在使用nvarcharvarchar类型时,这仅意味着在插入时保留尾随空格,而不是像在char和中那样用列的大小来填充值nchar
本M

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。


2

理想情况下,您希望减小长度,减小到合理大小的长度(500不是合理大小),并确保在数据过大并发送有用错误时捕获客户端验证。

尽管varchar实际上不会为未使用的空间保留数据库中的空间,但我记得SQL Server版本对数据库行的宽度大于一定数量的字节(不记得确切的计数)进行了说明,并实际上抛出了该错误。任何不适合的数据。这些字节中的一定数量是为SQL Server内部的内容保留的。


没错,这过去也是一个更大的问题。但是如今,空间确实很便宜,因此至少在我看来,我认为这不是一个值得考虑的大问题。
BBlake

1
@jcollum:在您的示例中,公司名称的大小似乎不合理500。
奥蒂斯(Otis)2010年

1
@BBlake:不管存储成本如何,如果SQL Server仍然具有行大小限制,那么无论您拥有多少存储都无所谓。您可以将所有内容存储在textblob中,但是有些SQL操作无法在varchar上进行,而是在blob上进行。
奥蒂斯(Otis)2010年

2
@Otis:我的意思是:公司名称的大小没有实际限制。除非某处有法律。因此,在那种情况下,我将该字段设为varchar(8000)并称之为一天。我的想法是这样的:真正的约束?varchar(x)。没有真正的约束?varchar(8000)。
jcollum 2010年

24
我认为30左右个字符是为城市名好,直到我看到的El Pueblo日纳斯特拉塞拉雷纳·洛杉矶德尔里奥日的Porciuncula
StuartLC
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.