SQL Server 中有关 varchar 大小调整的当前最佳做法是什么?

ari*_*600 14 performance sql-server best-practices varchar storage

我试图从存储和性能角度了解决定 varchar 列应该有多大的最佳方法。

性能
从我的研究来看,似乎varchar(max) 只应在您确实需要时使用;也就是说,如果该列必须容纳超过 8000 个字符,一个原因是缺乏索引(尽管我对一般的 varchar 字段的索引有点怀疑。不过,我对 DB 原则还很陌生,所以也许这是没有根据的) 和压缩(更多的是存储问题)。事实上,一般来说,人们似乎只推荐使用你需要的东西,当做 varchar(n)....oversizing 是不好的,因为查询必须考虑到最大可能的大小。但也有人表示,引擎将使用指示大小的一半作为数据平均实际大小的估计值。这意味着人们应该根据数据确定平均大小是多少,将其翻倍,并将其用作 n。对于具有非常低但非零可变性的数据,这意味着比最大尺寸大 2 倍,这看起来很多,但也许不是?见解将不胜感激。

存储
在阅读了行内与行外存储的工作原理后,并记住实际存储仅限于实际数据,在我看来,n 的选择实际上对存储几乎没有影响(除了确保它足够大以容纳所有东西)。即使使用 varchar(max) 也不会对存储产生任何影响。相反,如果可能,目标可能是将每个数据行的实际大小限制为 ~8000 字节。这是对事物的准确阅读吗?

上下文
我们的一些客户数据会稍微波动,因此我们通常将这些列的列设置得比它们需要的宽度稍宽一些,比如大 15-20%。我想知道是否还有其他特殊考虑;例如,和我一起工作的人告诉我使用 2^n - 1 个尺寸(不过我没有发现任何证据......)

我说的是初始表的创建。客户会告诉我们他们将开始向我们发送一个新表,并发送示例数据(或只是第一个生产数据集),我们会查看这些数据并在我们的一端制作一个表来保存数据。我们希望在我们的一端制作表格以处理未来的导入以及样本中的内容。但是,某些行肯定会变长,所以我们填充它们。

问题是多少,是否有技术指南?

Sol*_*zky 20

无论特定数据类型如何,您都需要能够存储应用程序请求存储的任何内容。您不能指定小于实际保存内容的最大大小的内容。

您也不需要,也不希望指定一个大于最大实际大小的列长度,出于各种原因:查询内存分配,可能填满最大行大小,并且没有留下任何空间来添加列未来等。

确实,可变长度字符串和二进制列没有固定长度数据类型(字符串/二进制/数字/日期等)所具有的存储含义(尽管其中一些含义可以通过数据压缩或使用SPARSE列定义来消除)选项)。但是,正如您所指出的,即使没有直接的存储影响,仍然存在高估查询所需内存的性能影响。

理智一点。仅使用您需要的东西。如果在不久的将来需要增加列长度的可能性很高,则可以考虑,但请记住,扩展列的大小比减少大小更容易。是的,将涉及一些工作,但由于这项工作只是“潜在的”,而过度调整对性能的影响是“实际的”,通常最好根据您的实际需要而不是您可能的情况来定义列-sorta 认为您将来可能需要。许多谈论的变化从未发生,而且所需的变化往往无法预见。用你所知道的去。

相反,如果可能,目标可能是将每个数据行的实际大小限制为 ~8000 字节。

我不完全确定你在这里得到了什么。SQL Server 将在物理上将您限制在 8000 字节以上。使用 LOB 类型 — VARCHAR(MAX)NVARCHAR(MAX)VARBINARY(MAX)XML和不推荐使用的TEXTNTEXTIMAGE类型 — 允许超出初始页面大小限制,但这只是由于放置了一个指针(16 个或更多字节,取决于类型,并且取决于使用MAX类型时行外存储的值的大小)。数据页的实际物理限制没有改变。

您的目标应该是使用最少的物理空间来存储应用程序/业务需要存储的内容,而不会破坏或截断,从而使不完整的值失去意义或导致下游出现问题。如果您需要存储 12,000 个字符的东西,请使用,VARCHAR(MAX)因为这正是所需要的。如果您要存储电话号码或邮政/邮政编码,那么使用 是不明智的VARCHAR(100),也是不负责任的VARCHAR(MAX)

我们的一些客户数据略有波动,因此我们通常将这些列的列设置得比它们需要的宽度稍宽,比如大 15-20%。我想知道是否还有其他特殊考虑;

不是所有系统都至少有一些波动的数据吗?任何存储人名的系统都符合条件,对吗?名字的长度有相当大的差异。然后你有像普林斯这样的人去把他们的名字改成一个符号,现在你有一个完全不同的问题,而不是长度。事情就是这样。

但是,请假装一下:“比需要的大15-20%”的值怎么可能不是实际需要的值?假设有一个关于添加新列的讨论,有人建议使用 50 个字符,然后其他人说,“好吧,60 个字符多出 20%,所以我们做 60 个,因为有人可能有 60 个字符。” 如果客户可能有 60 个是真的,那么 60 就是并且一直是实际需要的价值,而 50 一直是错误的。

当然,如果有一些关于数据来源的迹象会有所帮助,因为:

  1. 如果您将“URL”设为 1024 并且有人需要 1060,那么它需要是 1060(同样,如果您创建 URLVARCHAR并收到抱怨它弄乱了现在允许在域名中使用的 Unicode 字符,那么它需要是NVARCHAR),但
  2. 如果有人想在 500 个字符限制的评论字段中添加 1000 个字符,那么它仍然只需要500 个。人们可以在评论中不那么冗长(对我来说是一个巨大的挑战;-),但ProductSKU最好足够大以适应所有人客户的 SKU。

我说的是初始表的创建。客户会告诉我们他们将开始向我们发送一个新表,并发送示例数据(或只是第一个生产数据集),我们会查看这些数据并在我们的一端制作一个表来保存数据。我们希望在我们的一端制作表格以处理未来的导入以及样本中的内容。但是,某些行肯定会变长,所以我们填充它们。问题是多少钱,是否有技术指南?

你在这里做了很多假设。当然,有些字段可能会变大。但话又说回来,他们可能不会。或者,有些可能会变小。有些人可以从非 Unicode 变为 Unicode(一旦他们意识到世界变得越来越小,并且不能假设姓氏永远只有基本的 ASCII/美国英语字符)。或者,他们可以停止发送字段。或者他们可以在未来添加一个或多个字段。这和其他事情的任何组合。那么为什么只关注VARCHAR列呢?如果他们当前正在发送一个INT值并且在一两年内达到最大值并开始发送一个BIGINT? 如果他们有一个值为 0 - 5 的“状态”字段怎么办。你只是假设INT这是“填充”的,因为它允许增长,但可能应该是TINYINT

您唯一可以安全地预测的是,试图预测客户数据将如何变化的错误往往多于正确。正确是运气/巧合的问题(如果不是运气,那就去玩彩票吧;)。

所以指导方针是:

  1. 不要浪费时间和精力试图回答一个无法回答的问题。
  2. 相反,应专注于获取有关客户实际数据的尽可能多的信息,并继续这样做(即数据驱动的决策制定;-)。

您已经有了示例数据,太好了。但是,请不要忘记您还有客户的联系信息:电话和/或电子邮件。联系他们!向他们询问他们的数据规格(就像您的系统一样,他们系统中当前的数据最大长度可能为 35,但他们的系统将其定义为VARCHAR(50),并且他们的系统将接受该长度,在这种情况下,您应该使用50)。并且,询问他们是否有任何近期计划更改这些数据类型(类型和/或大小)。