【问题标题】:Best way to change clustered index (PK) in SQL 2005在 SQL 2005 中更改聚集索引 (PK) 的最佳方法
【发布时间】:2010-10-16 21:18:57
【问题描述】:

我有一个表,它在两列上有一个聚集索引 - 表的主键。 定义如下:

ALTER TABLE Table ADD  CONSTRAINT [PK_Table] PRIMARY KEY CLUSTERED 
(
  [ColA] ASC,
  [ColB] ASC
)WITH (SORT_IN_TEMPDB = OFF, IGNORE_DUP_KEY = OFF, ONLINE = OFF) ON [PRIMARY]

我想删除这个聚集索引 PK 并添加一个如下所示的聚集索引并使用非聚集索引添加一个主键约束,如下所示。

CREATE CLUSTERED INDEX [IX_Clustered] ON [Table] 
(
  [ColC] ASC,
  [ColA] ASC,
  [ColD] ASC,
  [ColE] ASC,
  [ColF] ASC,
  [ColG] ASC
)WITH (PAD_INDEX  = ON, STATISTICS_NORECOMPUTE  = OFF, SORT_IN_TEMPDB = OFF,     DROP_EXISTING = OFF, IGNORE_DUP_KEY = OFF, FILLFACTOR = 90, ONLINE = OFF, ALLOW_ROW_LOCKS  = ON, ALLOW_PAGE_LOCKS  = OFF) ON [PRIMARY]

ALTER TABLE Table ADD CONSTRAINT
  PK_Table PRIMARY KEY NONCLUSTERED 
  (
    ColA,
    ColB
  ) WITH( STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]

我打算只删除 PK 聚集索引,然后添加新的聚集索引,然后添加非聚集主键索引,但我了解到删除现有聚集索引会导致表数据重新排序(请参阅在这里回答What happens when I drop a clustered primary key in SQL 2005),我认为没有必要。该表正在敲 1 TB,所以我真的想避免任何不必要的重新排序。

我的问题是,从现有结构到所需结构的最佳方式是什么?

编辑:只是想澄清一下。该表为 1TB,不幸的是我没有空间来创建临时表。如果有办法在不创建临时表的情况下做到这一点,请告诉我。

【问题讨论】:

    标签: sql sql-server-2005 indexing primary-key clustered-index


    【解决方案1】:

    这不是您问题的完整答案,但请确保如果表上有任何其他索引,请先删除这些索引。否则,当您删除聚集索引时,SQL Server 将不得不重新构建它们,然后在您添加新的聚集索引时再次重新构建它们。通常的步骤是:

    1. 删除所有非聚集索引
    2. 删除聚集索引
    3. 添加新的聚集索引
    4. 重新添加所有非聚集索引

    【讨论】:

    • 嗯,那是我最初的计划,但是删除聚集索引的第二步会导致所有数据都被移动。我希望以某种方式合并第 2 步和第 3 步,以避免不必要的数据移动。
    【解决方案2】:

    如果您的表的大小达到 1 TB,并且其中可能有很多行,我强烈建议不要让聚集索引变得更胖!

    首先,删除和重新创建聚集索引将至少对所有数据进行一次洗牌 - 仅此一项就需要很长时间。

    其次,您尝试创建的大型复合聚集索引将显着增加所有非聚集索引的大小(因为它们包含每个叶节点上的整个聚集索引值,用于书签查找)。

    问题更多:你为什么要这样做?难道你不能用这些列添加另一个非聚集索引,以潜在地覆盖你的查询吗?为什么这必须是聚集索引?我看不出有什么好处……

    有关索引的更多信息,尤其是聚集索引的争论,请参阅 SQL Server 索引上的Kimberly Tripp's blog - 非常有帮助!

    马克

    【讨论】:

      【解决方案3】:
      1. 创建一个新表:

        CREATE TABLE newtable (colA INT, colB INT)
        
        • 将旧表中的所有值插入新表中:

          插入 INTO新表 选择 * 来自表

        • 删除旧表:

          DROP TABLE 表

        • 将新表重命名为旧表

          EXEC sp_rename 'newtable', 'table'

        • 建立索引:

          ALTER TABLE 表 添加约束 PK_Table PRIMARY KEY 非集群 ( 可乐, ColB ) WITH(STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]

      【讨论】:

      • 这不是一个选项。我有一个 1.5TB RAID 上的 1TB 表。
      • SQL Server 将需要空间用于重新排序和移动。如果空间不足,可以使用 DROP INDEX 中的 MOVE TO 选项在临时存储上创建表,然后在 RAID 上重新创建。
      • 您可以以块的形式传输行,并在进行时将它们从源中删除。不过,这可能是一个非常缓慢的过程。
      • 好的....为什么创建临时表比删除聚集索引并允许不必要的求助更好?似乎它会同样缓慢并且需要更多的工作。
      • 在此处查看如何估算您的新表大小:msdn.microsoft.com/en-us/library/ms187445.aspx
      【解决方案4】:

      聚集索引实际上并不会改变存储在它自己的表中的数据的物理顺序。从 SQL 6.5 开始就不是这样了。

      页面上的数据以正确的顺序存储。这些页面可以以任何物理顺序存储在磁盘上。

      【讨论】:

      • 是真的吗?我的印象是数据的物理顺序是由聚类键决定的。
      • 页面上的数据以正确的顺序存储。这些页面可以按任何物理顺序存储在磁盘上。
      • 您可能希望更新您的答案以包含此区别。
      猜你喜欢
      • 2010-10-09
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-05-01
      • 2010-11-03
      • 1970-01-01
      • 2020-03-24
      相关资源
      最近更新 更多