在slightly heated discussion on TDWTF中出现了一个关于数据库中varchar列大小的问题。
例如,取一个包含人名(只有姓名,无姓)的字段。很容易看出它不会很长。大多数人的名字少于10个字符,而20岁以上的人名很少。如果你要制作你的专栏,比如varchar(50),它肯定会保留你遇到过的所有名字。
然而,对于大多数DBMS而言,无论您创建varchar(50)还是varchar(255),它的大小或速度都没有区别。
那么为什么人们试图让他们的列尽可能小?我知道在某些情况下你可能确实想要限制字符串的长度,但大多数情况并非如此。如果有一个名字极长的人的罕见情况,那么更大的利润只会是有益的。
<小时/> 已添加:人们希望引用“无大小或速度差异”的陈述。好。他们在这里:
对于MSSQL: http://msdn.microsoft.com/en-us/library/ms176089.aspx
存储大小是输入的实际数据长度+ 2个字节。
对于MySQL: http://dev.mysql.com/doc/refman/5.1/en/storage-requirements.html
如果列值需要0 - 255字节,则为L + 1个字节;如果值可能需要超过255个字节,则为L + 2个字节
我找不到Oracle的文档,但我没有使用过其他DBMS。但我没有理由相信它有任何不同。
答案 0 :(得分:20)
我只能代表Oracle。如果输入值“SMITH”,VARCHAR2(50)和VARCHAR2(255)将占用完全相同的空间量并执行相同的操作。
然而,将所有文本列声明为VARCHAR2(4000)通常不是一个好主意的原因是列长度实际上是另一个约束。约束是业务规则的数据库实现,因此它们肯定是应该在数据库方面定义的东西。
作为一个例子。您可以在列上定义CHECK约束,以便它可以接受的值仅为“Y”和“N”。这使您的应用程序不必处理'y'和'n'甚至'1'和'0'。检查约束可确保您的数据符合预期标准。然后,您的应用程序代码可以对其必须处理的数据的性质做出有效的假设。
列长度定义在同一条船上。你声明一些东西是VARCHAR2(10),因为你不希望它接受'ABC123ZYX456'的条目(无论出于何种原因!)
在澳大利亚,我将STATE列定义为varchar2(3)因为我不希望人们输入“新南威尔士”或“南澳大利亚”。列定义几乎迫使它们作为“NSW”和“SA”输入。从这个意义上讲,VARCHAR2(3)几乎与实际指定CHECK IN('NSW','SA','VIC'等)约束一样是一个检查约束。
简而言之,正确的列长度是编码业务规则的一种方式。它们是另一种形式的约束。它们带来了约束的所有优点(并且遭受许多相同的缺点)。并且他们在很小程度上确保了“数据清洁度”,“适当的”约束也有助于。
我也不认为最好在客户端应用程序中粘贴这些东西,因为它更容易在那里进行更改。您有20,000人使用应用程序,即20,000次更新。你有一个数据库,这是一个更新。 “更容易更改客户端应用程序”参数(如果为true)可能意味着数据库只会被视为一个巨大的桶,其中所有聪明的逻辑都在客户端代码中处理。这是一个很大的讨论,但由于所有RDBMS都允许您在数据库本身中定义约束等,因此很明显至少有一个值得做的事情,即这种基本逻辑属于后端。
答案 1 :(得分:5)
我听说查询优化器确实考虑了varchar长度,但我找不到引用。
定义varchar长度有助于传达意图。定义的约束越多,数据越可靠。
答案 2 :(得分:3)
那么为什么人们试图让他们的列尽可能小?我不相信让它们尽可能小,而是适当地调整它们的大小。使(n)varchars变小而不是更大的一些原因:
1)对于较大的字段,使用数据库的所有客户端必须能够处理完整大小。例如,采用一个系统,其中包含每个字段255个字符的美国地址:(我相信,与您引用的TDWTF类似。)
现在,您的数据输入屏幕将需要允许并显示每个字段255个字符。不是很难,但是对于较大的字段不太可能看起来很好打印发票,你需要断行逻辑来处理大字段。取决于工具,不是那么难。
但我不想要为每个字段或其中任何一个字段可能包含255个字符的信封格式化地址的问题。如果场地太长而不适合,你会截断吗?很棒的人有“House Number Streat Number的地址1号线......等等等等......公寓号111”。你会丢掉重要的公寓号码。你要打包吗?多少?如果你不能把它放在信封上的小盒子里怎么办?提出异常,并有人给它发信吗?
2)虽然varchar(50)与varchar(255)中保存的10个字符的数据不会影响大小或速度,但允许255个字符可以获得更多空间。如果所有字段都很大,那么你可以在SQL Server 2000中达到大小限制。(我还没有读过2005和2008以查看它们是否可以处理超过一页的行。)而对于Oracle,您可以使用更大的字段如果某人实际使用了所有可用字符,则会发生行链接。
3)索引的大小限制比叶页更严格。如果创建的varchars太大,则可能会排除索引,尤其是复合索引。
另一方面,我的地址有一长串第1行,并且对于不允许输入完整内容的网站感到沮丧。
答案 3 :(得分:3)
一个重要的区别是指定一个任意大的限制[例如VARCHAR(2000)
],并使用不需要限制的数据类型[例如VARCHAR(MAX)
或TEXT
]。
PostgreSQL将其所有固定长度VARCHAR
基于其无限制TEXT
类型,并动态决定每个值如何存储该值,包括将其存储在外-页。在这种情况下,长度说明符实际上只是一个约束,实际上不鼓励使用它。 (ref)
其他DBMS要求用户选择是否需要“无限制”的页外存储,通常需要相关的便利和/或性能成本。
如果使用VARCHAR(<n>)
优于VARCHAR(MAX)
或TEXT
,则必须在设计表时为<n>
选择一个值。假设表行或索引条目有一些最大宽度,则必须应用以下约束:
<n>
必须小于或等于<max width>
<n> = <max width>
,表/索引只能有一列<x>
列,其中(平均)<n> = <max width> / <x>
因此不的情况是<n>
的值仅作为约束,<n>
的选择必须是设计的一部分。 (即使您的DBMS没有硬性限制,也可能有性能原因将宽度保持在一定限度内。)
您可以使用上述规则根据表格的预期体系结构(考虑到未来更改的影响)分配{em>最大值<n>
。但是,根据每列中预期的数据定义<n>
的最小值更有意义。最有可能的是,您将扩展到最近的“整数” - 例如您将始终使用VARCHAR(10)
,VARCHAR(50)
,VARCHAR(200)
或VARCHAR(1000)
,以最适合的为准。
答案 4 :(得分:2)
在我看来,对此的简单回答是你不能将该列用作索引键,如果你需要任何索引,你基本上被迫使用全文...这是关于使用varchar(max)柱。在任何情况下,只要你[可]想要应用任何索引,“正确大小”列就会很有意义;更新可变长度列可能是一种代价高昂的操作,因为这些没有到位并且可能/将导致一定程度的碎片。
所有关于MS SQ-Server。
答案 5 :(得分:1)
我将用一个问题回答你的问题:如果varchar(50)和varchar(255)之间的DBMS没有区别,为什么DBMS会让你区分?为什么DBMS不会简单地说“使用varchar最多xxx字符,而text / clob /等等。”当然,也许Microsoft / Oracle / IBM可能会因历史原因而保留长度定义,但DBMS如同具有多个存储后端的MySQL一样 - 为什么每个都实现可定义的字符列长度?
答案 6 :(得分:1)
如果要打印标签,通常希望字符串不超过35个字符。这就是为什么你想要控制你将要使用的Varchar的大小 将用于打印标签的线条。
答案 7 :(得分:0)
如果您允许数据长度超过255并且有人通过MS Access链接到数据,则无法使用数据来连接表(作为备注字段提供)。如果数据导出为excel,则每个字段限制为255个字符。创建数据集时应考虑与其他程序的兼容性 数据质量控制就是控制进入环境的数据。您需要存储超过255个字符的内容?有时候数据需要超过255个字符,但它们之间应该相差很远,并且应该用作可用于分析的字段的支持性补充信息
答案 8 :(得分:0)
大小很重要,它会影响性能!在 mssql 中,执行计划程序会做出假设,而这个假设可能会造成伤害,当计划某种 varchar 列时,计划程序将平均行大小预测为声明长度的 50%,+ 一点开销,因此如果您声明 varchar(200)执行计划器估计行大小约为 110 字节,如果行填充到 80%,执行计划将被迫使用 tempdb 对行进行排序,而不是在内存中排序。我在此处提供了证明和完整示例:https://kisunu.no/index.php?pid=20130