20

关于 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。但我没有理由相信那里有什么不同。

4

9 回答 9

23

我只能代表甲骨文。如果输入值“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 次更新。你有一个数据库,这是一个更新。“更容易更改客户端应用程序”参数,如果为真,则可能意味着数据库只是被视为一个巨大的比特桶,所有聪明的逻辑都在客户端代码中处理。这是一个很大的讨论,但由于所有 RDBMS 都允许您在数据库本身中定义约束等,因此很明显,至少有一个值得说明的情况,即此类基本逻辑属于后端。

于 2009-08-14T01:05:07.200 回答
5

我听说查询优化器确实考虑了 varchar 长度,但我找不到参考。

定义 varchar 长度有助于传达意图。定义的约束越多,数据就越可靠。

于 2009-08-11T16:58:53.497 回答
3

那么,为什么人们要尽可能地缩小他们的列呢?我不相信让它们尽可能小,但要适当地调整它们的大小。使 (n)varchars 变小而不是变大的一些原因:

1)对于更大的字段,所有使用数据库的客户端必须能够处理完整的大小。例如,以一个拥有每个字段 255 个字符的美国地址的系统为例:(类似于您引用的 TDWTF,我相信。)

  • 地址第一行
  • 地址行 2
  • 城市
  • 状态
  • 邮政编码

现在,您的数据输入屏幕将需要允许并显示每个字段 255 个字符。不难,但不太可能在较大的字段中看起来不错 打印发票,您将需要换行逻辑来处理大字段。取决于工具,并不难。

但我不希望为每个字段或任何一个字段可能有 255 个字符的信封格式化地址的问题。如果字段太长而无法容纳,您是否要截断?伟大的人的地址行 1 是“House Number Streat Number ... blah blah blah ... Appartment number 111”。你会砍掉重要的公寓号码。你要包起来吗?多少?如果您无法将其放入信封上的小空间中怎么办?提出一个例外并让某人亲手给它写信?

2) 虽然 varchar(50) 与 varchar(255) 中保存的 10 个字符的数据不会影响大小或速度,但允许 255 个字符允许占用更多空间。如果所有字段都那么大,您可能会在 SQL Server 2000 中达到大小限制。(我还没有阅读 2005 和 2008 年的内容,看看它们是否可以处理大于一页的行。)对于 Oracle,更大的大小允许行如果有人实际使用了所有可用的字符,就会发生链接。

3) 索引比叶子页有更严格的大小限制。如果您创建的 varchar 太大,您可能会排除索引,尤其是复合索引。


另一方面,我的地址有很长的第一行,并且对不允许输入完整内容的网站感到沮丧。

于 2009-08-11T16:45:45.707 回答
3

一个重要的区别是指定任意大的限制[例如VARCHAR(2000)]和使用不需要限制的数据类型[例如VARCHAR(MAX)TEXT]。

PostgreSQL 将其所有固定长度VARCHAR的 s 基于其无限TEXT类型,并动态决定每个值如何存储该值,包括将其存储在页外。在这种情况下,长度说明符实际上只是一个约束,实际上不鼓励使用它。(参考)

其他 DBMS 要求用户选择是否需要“无限制”、页外存储,通常会带来便利和/或性能方面的相关成本。

如果使用VARCHAR(<n>)over VARCHAR(MAX)or有优势TEXT,那么您必须<n>在设计表格时选择一个值。假设表行或索引条目有某个最大宽度,则必须应用以下约束:

  1. <n>必须小于或等于<max width>
  2. 如果<n> = <max width>,表/索引只能有 1 列
  3. 通常,表/索引只能包含<x>(平均)<n> = <max width> / <x>

因此, 的值不仅仅<n>充当约束,而且 的选择<n>必须是设计的一部分。(即使您的 DBMS 中没有硬性限制,也可能出于性能原因将宽度保持在一定范围内。)

您可以使用上述规则根据表的预期架构(考虑到未来更改的影响)来分配最大值。但是,根据每列中的预期数据定义 的最小值<n>更有意义。最有可能的是,您将扩展为最接近的“整数” - 例如,您将始终使用、、或,以最适合的为准。<n>VARCHAR(10)VARCHAR(50)VARCHAR(200)VARCHAR(1000)

于 2009-08-17T19:12:14.800 回答
2

在我看来,对此的简单回答是,您不能将该列用作索引键,如果您需要任何索引,则基本上被迫使用全文......这是关于使用 varchar(max) 列的。在任何情况下,只要您 [可能] 想要应用任何索引,“调整大小”列就很有意义;更新可变长度列可能是一项代价高昂的操作,因为这些操作没有到位并且可能/将导致一些碎片。

所有关于 MS SQ-Server。

于 2009-08-18T19:17:52.893 回答
1

我会用一个问题来回答你的问题:如果 varchar(50) 和 varchar(255) 之间的 DBMS 没有区别,为什么 DBMS 会让你做出区分?为什么 DBMS 不简单地说“使用 varchar 最多 xxx 个字符,而 text/clob/etc. 用于其他任何内容”。当然,也许 Microsoft/Oracle/IBM 可能出于历史原因保留长度定义,但是 DBMS 像 MySQL 这样具有多个存储后端的情况如何——为什么每个都实现可定义的字符列长度?

于 2009-08-12T17:35:46.550 回答
1

如果要打印标签,通常希望字符串不超过 35 个字符。这就是为什么您希望对将用于接受将用于打印标签的行的 Varchar 的大小进行一些控制的原因。

于 2013-02-14T20:09:51.473 回答
0

如果您允许数据​​长度超过 255 并且有人通过 MS Access 链接到数据,则数据不能用于连接表(作为备注字段进入)。如果将数据导出到 Excel,则每个字段将限制为 255 个字符。创建数据集时应考虑与其他程序的兼容性。
数据质量控制就是控制进入您环境的数据。超过 255 个字符需要存储什么?有时数据需要超过 255 个字符,但它们之间应该相距甚远,并且应该用作可用于分析的字段的支持性补充信息

于 2018-05-21T08:47:54.423 回答
0

尺寸很重要,它会影响性能!在 mssql 中,执行计划程序会做出假设,并且这种假设可能会造成伤害,当计划某种 varchar 列时,计划程序将平均行大小预测为声明长度的 50%,+ 一点开销,所以如果您声明 varchar(200)执行计划程序估计行大小约为 110 字节,如果行填充到 80%,则执行计划将被迫使用 tempdb 对行进行排序,而不是在内存中排序。我在这里提供了证明和完整示例:https ://kisunu.no/index.php?pid=20130

于 2021-03-12T18:25:54.780 回答