SQL Server最大行大小与Varchar(Max)大小

3
我正在尝试估计SQL Server 2008 R2的数据库大小。我有一张表,其中包含一个 INTEGER 主键和39个类型为 VARCHAR(MAX)的文本列。
我已经搜索并找到了两种说法。
  • 每行最多可以包含8,060字节。
  • Varchar(max)的最大存储容量为2 GB。
我对如何估计大小感到困惑。如果行有限制,如何在每个列中存储2 GB?
我不是数据库专家,可能理解不正确。
请问有人可以解释如何估算吗?
谢谢

2
你看过这个链接吗?https://dev59.com/zWsz5IYBdhLWcg3wcnZb 我希望它能对你有所帮助。 - Timoshenko
你是想获取当前大小,还是想知道在添加一定行数后它可能会有多大? - Solomon Rutzky
"大型"数据类型,如 VARCHAR(MAX)VARBINARY(MAX) 与其他数据类型处理方式不同。由于它们可以容纳高达2GB的数据,因此可能会跨越许多"溢出"页面。在这种情况下,它们将占用基本数据页上一定数量的存储空间(具体文档中有说明-暂时不清楚),而intdatetime等其他列则在基本页上占用固定的存储空间。 - marc_s
@srutzky 我正在尝试找出它可能有多大。 - Shoaib Ijaz
取决于列将要存储的内容。一行可以存储140字节,而另一行可以存储78千兆字节,具体取决于数据。 - Sean Pearce
2个回答

4
在Microsoft SQL Server中,数据(包括索引)存储在一个或多个8k(8192字节)的“页面”中。有不同类型的页面可用于处理各种情况(例如数据、LOB、索引、AllocationMap等)。每个页面都有一个标题,其中包含关于该页面及其内容的元数据。
大多数数据存储在行本身中,而一个或多个这些行又存储在一个“行内数据”页面中。由于行头占用的空间,对于“行内”数据,最大的行大小为8060字节。
但是,并非所有数据都存储在行中。对于某些数据类型,实际上可以将数据存储在“LOB数据”页面中,同时在“行内”数据中留下指针。
  • 遗留/已弃用的LOB类型(TEXTNTEXTIMAGE),默认情况下始终将其数据存储在LOB页上,并始终使用指向该LOB页的16字节指针。

  • 较新的LOB类型(VARCHAR(MAX)NVARCHAR(MAX)VARBINARY(MAX)XML),默认情况下会尝试直接将数据放入行中,如果可以容纳。否则,它将在LOB页面上存储数据,并使用24-72字节的指针(取决于LOB数据的大小)。

这是如何在单行中存储高达78 GB + 4字节(别忘了INT主键;-)的方法:最大行大小将在940字节((39 * 24)+4)和2812字节((39 * 72)+4)之间。但再次强调,这只是最大范围;如果39个VARCHAR(MAX)字段中的每个数据只有10个字节,那么所有数据都将以行内方式存储,行大小将为394字节((39 * 10)+4)。
考虑到您有这么多可变长度字段(无论它们是否为MAX),唯一估算未来行大小的方法是对将在此表中存储的数据有一个很好的了解。尽管如此,一个包含全部或大多数MAX数据类型的表意味着没有人真正知道将在此表中存储什么数据。
另外应该指出,这是一个糟糕的模型表 / 糟糕的MAX数据类型字段使用,并且应加以重构。
关于数据页面结构的更多详细信息,请参见我的答案DBA.StackExchange问题:

数据长度的总和与sys.allocation_units表的大小不匹配


Soloman,你有一个链接描述了你所说的24-72字节的开销吗?我问这个问题是因为我做了一些测试,发现这是非常真实的,而且不仅仅是存储16字节指针。 - Jeff Moden
嗨@JeffModen。是的,16字节指针大多只用于已弃用的LOB类型(IMAGETEXTNTEXT),尽管如果使用sp_tableoption设置text in row(不确定有多少人知道该选项),这并不总是正确的。或者,另一个不经常出现的情况是使用sp_tableoptionMAX类型设置large values out of row,这会导致它们始终使用16字节指针。但请查看我回答末尾的链接,因为它指向了我刚刚更新了更详细的答案,并附有外部参考和测试脚本。 - Solomon Rutzky
谢谢Soloman。我在http://improve.dk/what-is-the-size-of-the-lob-pointer-for-max-types-like-varchar-varbinary-etc/上找到了Mark S. Rasmussen的链接。 - Jeff Moden
@JeffModen 所以,您没有看我在此答案底部链接的另一个答案吗?;-) 不仅那个答案中有相同的链接,而且我还添加了一些马克博客文章中未提到的细节(以及一个链接到一个测试脚本,可以带您完成大部分操作)。此外,我发现内联根的上限是42,000,而马克的帖子则说明限制只有40,000。这个答案只是基于那个其他答案的部分总结。请查看其他答案(“SUM of DATALENGTHs…”链接)。 - Solomon Rutzky
不,我确实没有。你提到的链接标题中没有任何提示表明我正在寻找的内容,而链接上方的描述说它是有关数据页面结构的更多信息,而我已经知道页面级别的信息。我只需要快速回答24-72小时的问题。既然你知道24-72数字的来源,如果你在这个帖子上发布一个直接链接就好了。现在看着那篇文章,Solomon写得很好。 - Jeff Moden
@JeffModen 抱歉,我并不是故意要刁难。我只是觉得在这里评论中放太多信息了,而且那个链接虽然是一个很好的资源,但并没有涵盖我在另一个答案中提到的所有内容。我认为我的测试脚本涵盖了一两个场景,这些场景在Mark的帖子中没有涵盖到。谢谢,希望你找到了你想要的信息。 - Solomon Rutzky

1

当使用Varchar(MAX)时,如果内容小于8000字节,数据可以存储在行内(称为页面)中。 如果内容大于8000字节,则数据被存储为LOB(“离开页”),并且仅在页面中存储对实际位置的引用。 考虑到数据可能在Varchar(MAX)列中具有任意长度,我真的不知道估计整个数据库大小的任何合理方法。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接