0

更新相对较大的表(约 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 备份的,所以我想跳过任何事务更新)
4

3 回答 3

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 列不回收列占用的空间

于 2012-10-02T12:56:10.433 回答
1
  1. 删除您正在更新的表上的索引,并在更新完成后重新创建。
  2. 更新完成后删除您正在更新的表上的约束并适当地重新创建(毕竟您正在更改引用)。
  3. 关闭正在更新的表上的触发器,并在更新完成后启用。
  4. 您可能需要考虑运行批处理。我个人会创建一个循环并一次批量更新 10k 行。这似乎在我的硬件上造成的问题最少(磁盘空间不足等)。您可以订购更新并跟踪 PK,这样您就知道自己在哪里。或者创建一个在更新特定记录时设置的位列;这种方法总体上可能会更容易,因为您根本不需要跟踪 PK。

这种循环的示例可能如下所示:

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
于 2012-10-02T13:07:02.590 回答
0

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

问题是您必须将许多 device_id 值塞入 person 表的一列中——这就是为什么您首先需要一个 group 表。

于 2012-10-02T12:59:38.750 回答