修改表中每一行的最快方法

时间:2012-10-02 12:51:04

标签: sql sql-server sql-update

更新相对较大的表(约7000万行)的推荐方法是什么,以替换id为不同表的外键列(由当前键间接链接) ?

假设我有三张桌子:

Person
  Id long,
  Group_id long   --> foreign key to Group table

Group
  Id long
  Device_id long  --> foreign key to Device table

Device
  Id long

我想更新Person表以获得Device表的直接外键,即:

Person
  Id long,
  Device_Id long  --> foreign key to Device table

Device
  Id long

查询看起来像这样:

-- replace Group_id with Device_id
update p from Person p
  inner join Group g
  on g.Id = p.Group_id
set p.Group_id = g.Device_id

我首先删除FK约束,然后重命名该列。

  • 这会有用吗?
  • 有更好的方法吗?
  • 我可以加快速度吗? (当此查询正在运行时,其他所有内容都将脱机,服务器将进行UPS备份,因此我希望跳过任何事务更新)

3 个答案:

答案 0 :(得分:1)

如果你正确地写了UPDATE(假设这是SQL Server)

,它会工作
update p
set p.Group_id = g.Device_id
from Person p
inner join Group g on g.Id = p.Group_id

除此之外,重新使用,然后重命名列*是一个非常聪明的举动。除非您希望使用WHILE循环和person.Id标记将更新分解为批次,否则无法想出任何更快速的方法。

* - ALTER TABLE DROP COLUMN DOES NOT RECLAIM THE SPACE THE COLUMN TOOK

答案 1 :(得分:1)

  1. 删除要更新的表上的索引,并在更新完成后重新创建。
  2. 删除正在更新的表上的约束并在更新完成后适当地重新创建(毕竟您正在更改引用)。
  3. 关闭要更新的表上的触发器,并在更新完成后启用。
  4. 您可能需要考虑运行批次。我个人会一次创建一个循环并批量更新10k行。这似乎导致我的硬件上出现最少的问题(磁盘空间不足等)。您可以订购更新并跟踪PK,以便了解您的位置。或者创建在更新特定记录时设置的位列;这种方法可能会使整体更容易,因为您根本不需要跟踪PK。
  5. 这种循环的一个例子可能如下所示:

    select top 1 * from table
    
    DECLARE @MinPK BIGINT
    DECLARE @MaxPK BIGINT
    SET @MinPK=0
    SET @MaxPK=0
    
    WHILE @@ROWCOUNT>0
    BEGIN
        SELECT
            @MaxPK=MAX(a.PK)
        FROM (
            SELECT TOP 3
                PK
            FROM Table
            WHERE PK>@MinPK
            ORDER BY PK ASC
        ) a
    
        --Change this to an update
        SELECT
            PK
        FROM Table
        WHERE PK>@MinPK
        AND PK<=@MaxPK
    
        SET @MinPK=@MaxPK
    END
    

答案 2 :(得分:0)

你的想法不会“奏效”,除非每组只有一个设备(这可能是荒谬的,所以我不假设)。

问题在于你必须将许多device_id值填入person表的一列中 - 这就是你首先得到一个组表的原因。