寻找ROW_OVERFLOW_DATA如何发生的精确度

jfr*_*how 1 sql-server optimization database-design sql-server-2005 normalization

我目前正处于为CRM应用程序中的大型模块重写计划的初始阶段.

我目前正在研究的一个领域是数据库优化,我还没有做出任何决定,但我只是想确保我理解ROW_OVERFLOW_DATA的概念 - http://msdn.microsoft.com/en-us/library/ ms186981.aspx

我们正在使用SQL Server 2005,我的理解是行大小限制是8,060字节,之后会发生溢出.

我运行了一个查询来获取特定读取密集型数据库的最大行大小

SELECT OBJECT_NAME (sc.[id]) tablename
, COUNT (1) nr_columns
, SUM (sc.length) maxrowlength
FROM syscolumns sc
join sysobjects so
on sc.[id] = so.[id]
WHERE so.xtype = 'U'
GROUP BY OBJECT_NAME (sc.[id])
ORDER BY SUM (sc.length) desc
Run Code Online (Sandbox Code Playgroud)

这给了我一些表格,其最大长度略高于8,000,但低于10,000.另一个查询显示平均行大小实际上非常小,大约1,000字节.

我的问题是:基于每一行是ROW_OVERFLOW_DATA还是每列?一旦扩展了8,060字节的限制,导致它溢出的整个列移动到另一个页面,还是只有特定的行?

因此,例如给出以下简化模式:

col1 (int) | col 2 (varchar (4000)) | col 3(varchar(5000))
    1      |    4000 characters   |    5000 characters ***This row is overflowing
    2      |    4000 characters   |    100 characters
    3      |    150 characters    |    150 characters
    4      |    500 characters    |    600 characters
Run Code Online (Sandbox Code Playgroud)

第1行到第4行的第3列是否会被24字节指针或只有rowID 1取代?

我想知道是因为如果它的每一行都有一个指针,那么修复它就变得很重要,如果它只有几行,我们就可以获得性能.

此外,我已经看到许多博客建议将可空列移到数据库的末尾,这样如果值实际上是NULL,则它们不占用任何行空间.这是真的?我们倾向于将时间戳和跟踪列保留在最后,因为它更容易可视化.现在我想知道是否我们不应该进一步向上移动,因为它们永远不会为NULL.

gbn*_*gbn 5

如果你有一行,比如一个1亿溢出,你会移动整列吗?没有.

作为参考,来自Paul Randal的一篇Technet文章是这个东西的上帝(我的大胆)

您正在使用,行溢出的功能,是伟大的,允许偶尔排长于8,060字节,但它不是非常适合于广大行是放大,并可能导致查询性能下降,因为你是经历.

这样做的原因是,当一个行即将成为过大的,可变长度列中的一个行中的推"行外".这意味着该列取自数据或索引页面上的行并移动到文本页面.代替旧列值,替换指针指向数据文件中列值的新位置.

MSDN(我的大胆)

ROW_OVERFLOW_DATA分配单位

对于表(堆或聚簇表),索引或索引视图使用的每个分区,都有一个ROW_OVERFLOW_DATA分配单元.此分配单元包含零(0)页,直到IN_ROW_DATA分配单元中具有可变长度列(varchar,nvarchar,varbinary或sql_variant)的数据行超过8 KB行大小限制.达到大小限制时,SQL Server将具有该最大宽度的列移动到ROW_OVERFLOW_DATA分配单元中的页面.在原始页面上保留了一个指向该行外数据的24字节指针.

至于你的NULLable列,这是错误的.无论列表顺序中的列顺序如何,都可以将NULLable列存储在磁盘结构的末尾.Paul Randal的参考文献:存储引擎内部:再次对记录进行解剖.我在这里的任何一些先前的答案在SO