如何加快群集列的大规模更新?

时间:2009-06-19 06:37:40

标签: sql sql-server performance indexing

我有一个非常大的表:超过20万行,我需要更新大约5% - 或100万行。

不幸的是,我正在更新用作聚簇索引的(int)列。

我的问题是: 更新这些行的最快方法是什么?

我尝试过直接更新行:

update t1
set t1.groupId = t2.groupId
from
    table t1
join newtable t2 on t1.email = t2.email

但这需要太长时间(我在3小时后停止了)

我认为这是因为整个行(有2个日期时间,2个varchars和2个int)正在为每次更新移动。

如果我首先删除聚簇索引,然后执行更新,然后重新创建聚簇索引,该怎么办?会更快吗?

注意:我在电子邮件上有非聚集索引,以防有人认为它是查询的选择部分很慢。不是。

3 个答案:

答案 0 :(得分:8)

这就是我所做的(而且速度要快得多):

  1. 我删除了聚集索引。
  2. 我还丢掉了外键 引用(另外两个int 列)。
  3. 我运行了更新声明
  4. 我重新创建了索引,这比预期的要快。 (这是我先问过SO的原因)。
  5. 这使整个过程缩短到几秒钟。 是的,约15秒内约有100万行。

    第二步是至关重要的,因为外键强制更新在相关表上执行某种线程,每个表都有大量行。

    由于这些外键查找,物理读取次数增加了两倍。

    我不确定为什么SQL Server需要这样做,但我的猜测是它仍然执行完整性检查,即使我没有更新该列但是我正在移动整行(群集列更新)。 / p>


    作为旁注,我还尝试分批运行更新:

    update top(1000) t1
    set t1.groupId = t2.groupId
    from
        table t1
    join newtable t2 on t1.email = t2.email
    

    这很好(似乎每批可扩展到大约10K),但每批次仍然是1-2分钟。


    总之,我已经了解到,对于批量更新,暂时删除索引可能非常有用。

答案 1 :(得分:2)

我认为之前的评论是正确的。你有点回答了自己的问题。

因为

  

聚簇索引排序和存储   表中的数据行基于它们   键值(source msdn),

您可能最好只删除聚集索引(将索引保留在电子邮件中)。完成操作后,重新创建聚簇索引。 只要groupid没有涉及任何其他索引,我就不会触及它们。如果组ID包含在其他索引中,则删除它们。我会留下至少一个电子邮件索引,只是为了加快加入。

答案 2 :(得分:-2)

为什么不执行以下操作:

  • 创建不同的列(其中一个varchar)聚集索引
  • 在groupId上创建索引
  • 更新
  • 然后反转过程。

这应该更快。