【问题标题】:Adding a column efficently in SQL Server在 SQL Server 中有效地添加列
【发布时间】:2010-10-19 21:06:45
【问题描述】:

我想在具有大量行和许多索引的表中添加一个整数列(它是一个数据仓库事实表)。

为使行宽尽可能窄,此表中的所有列都定义为非空。所以我希望新列不为空,默认为零。

根据经验,添加此列需要一些时间,可能是因为数据库需要用填充值的新列重写所有行。这大概会涉及到更新聚集索引和所有非聚集索引。

所以我应该在添加列之前删除所有索引,然后重新创建它们。 或者有更简单的方法吗?

另外,我真的不明白为什么添加一个可为空的列要快得多。为什么这不涉及重写记录并为每一行翻转一个额外的 Is Null 位。

【问题讨论】:

  • “为使行宽尽可能窄,此表中的所有列都定义为非空” - 这是如何工作的?

标签: sql-server database performance indexing nullable


【解决方案1】:

SQL Server 是一个面向行的数据库。这与面向列的数据库形成对比。这意味着在 SQL Server 中,给定行的所有数据都存储在磁盘上。举个例子:

假设您有一个包含 3 列的 Customer 表,FirstName、MiddleInitial 和 LastName。然后,假设此表中有 Jabba T. Hutt、Dennis T. Menace 和 George W. Bush 的 3 条记录。

在面向行的数据库(如 SQL Server)中,记录将按如下方式存储在磁盘上:

贾巴、T、赫特;丹尼斯,T,威胁;乔治、W、布什;

相比之下,面向列的数据库会将记录存储在磁盘上,如下所示:

贾巴、丹尼斯、乔治; T、T、W;赫特威胁,布什;

列组合在一起而不是行。

现在,当您在面向行的数据库(例如 SQL Server)中向表中添加列时,必须将每列的新数据插入到现有行旁边,从而转移需要大量读/写操作。因此,如果您要为默认为“先生”的客户前缀插入一个新列,您会得到以下结果:

先生,贾巴,T,赫特;丹尼斯先生,T,威胁;乔治、W、布什先生;

如您所见,所有原始数据都已向右移动。另一方面,当您插入一个默认为 NULL 的新列时,不必将新数据放入现有行中。因此,移位更少,需要更少的磁盘读/写操作。

当然,这是对磁盘上实际情况的过度简化。在处理索引、页面等时,还有其他一些事情需要考虑。但是,它应该可以帮助您了解情况。

为了澄清我根本不建议您迁移到面向列的数据库,我只是将这些信息放在那里以帮助解释面向行的含义。

【讨论】:

    【解决方案2】:

    这将需要更新聚集索引,是的 - 毕竟这 IS 是表数据。

    但我不明白为什么必须更新任何非聚集索引 - 您的新列不会成为任何非聚集索引的成员。

    另外,我看不出在这种情况下删除和重新创建索引会对您有什么好处。如果您从另一个表或数据库批量加载数百万现有行 - 是的,那么它可能会更快(由于 INSERT 更快) - 但添加列并不会真正受到任何索引或约束的影响,我不认为。

    马克

    【讨论】:

    • “但是我不明白为什么必须更新任何非聚集索引” - 添加非空列需要删除和重新创建表,因此所有的副产品索引也必须被删除和重新创建。
    【解决方案3】:

    “另外,我真的不明白为什么添加一个可为空的列要快得多。为什么这不涉及重写记录并为每一行翻转一个额外的 Is Null 位。”

    添加可为空的列只会更改表的定义。个人记录不受影响。

    【讨论】:

      猜你喜欢
      • 2012-05-07
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-06-11
      • 1970-01-01
      • 1970-01-01
      • 2013-05-06
      相关资源
      最近更新 更多