【问题标题】:Looking for precision on how ROW_OVERFLOW_DATA happen寻找 ROW_OVERFLOW_DATA 如何发生的精确度
【发布时间】:2011-08-27 14:53:20
【问题描述】:

我目前正处于为我们的 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

这给了我几张 maxrowlength 略高于 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

第 1 行到第 4 行的第 3 列会被替换为 24 字节指针还是仅替换为 rowID 1?

我想知道因为如果每行都有一个指针,那么修复它就变得很重要,如果它只有几行,也许我们可以承受性能损失。

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

【问题讨论】:

    标签: sql-server sql-server-2005 database-design optimization normalization


    【解决方案1】:

    如果你有一行,比如说,一亿人溢出,你会移动整列吗?没有。

    作为参考,来自 Paul Randal 的 technet article,他是这些东西的神(我的大胆)

    您正在使用的行溢出功能非常适合允许偶尔行超过 8,060 字节,但它不太适合大多数行 strong> 过大并可能导致查询性能下降,正如您所经历的那样。

    这样做的原因是,当行即将变得过大时,行中的可变长度列之一被推到“行外”。这意味着该列取自数据或索引页上的行并移至文本页。代替旧的列值,替换为指向数据文件中列值的新位置的指针。

    还有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 列,这是错误的。不管表定义中的列顺序如何,可空列都存储在磁盘结构的末尾。以及来自Paul Randal: Inside the Storage Engine: Anatomy of a record 的引用。任何以前的答案from me here on SO

    【讨论】:

      【解决方案2】:

      仅当特定行溢出时,该行的违规数据才会被移到单独的溢出页面中 - 想象一下,如果仅仅因为一列中的一个值溢出而需要重建整个表,那会很头疼!

      我没有听说过将 NULLables 移到表末尾的想法 - 我必须检查一下!

      【讨论】:

      • Null适用于可变长度列,并且您最终只保存了列偏移数组中的 2 个字节。
      • @Martin - 其中一个“在 0.1% 的情况下可能值得了解”的样式优化会导致您的表格结构混乱?
      猜你喜欢
      • 2011-07-16
      • 2013-04-19
      • 1970-01-01
      • 1970-01-01
      • 2016-11-27
      • 1970-01-01
      • 1970-01-01
      • 2019-05-22
      • 2012-06-08
      相关资源
      最近更新 更多