0

外部キー列を別のテーブル(現在のキーによって間接的にリンクされている)のIDに置き換えるために、比較的大きなテーブル(〜7000万行)を更新するための推奨される方法は何ですか?

3つのテーブルがあるとしましょう。

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 COLUMNは、列が取ったスペースを再利用しません

于 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

グループごとにデバイスが1つしかない場合を除いて、あなたのアイデアは「機能」しません(これはばかげているので、そうではないと思います)。

問題は、personテーブルの1つの列に多くのdevice_id値を詰め込む必要があることです。これが、そもそもグループテーブルを持っている理由です。

于 2012-10-02T12:59:38.750 に答える