結合せずにこの問題を解決できます。つまり、パフォーマンスが向上するはずです。アイデアは、各object_idの行番号を数えて、object_idでデータをグループ化することです。これが「partitionby」が行うことです。次に、row_numが1より大きい場所を更新できます。これにより、最初のオブジェクトを除くすべての複製されたobject_idが更新されます。
update t set t.status_val = 'some_status'
from (
select *, row_number() over(partition by object_id order by (select null)) row_num
from foo
) t
where row_num > 1
82944レコードのテストテーブルでは、パフォーマンスはそのようなものでした(マイレージは異なる場合があります!):テーブル'テスト'。スキャンカウント5、論理読み取り82283、物理読み取り0、先読み読み取り0、lob論理読み取り0、lob物理読み取り0、lob先読み読み取り0。CPU時間=141ミリ秒、経過時間=150ミリ秒。
>内部結合を使用してこの問題を解決することもできますが、一般に、これにより論理的な読み取りが増え、CPUが高くなります。
テーブル'テスト'。スキャンカウント10、論理読み取り83622、物理読み取り0、先読み読み取り0、lob論理読み取り0、lob物理読み取り0、lob先読み読み取り0。表'ワークファイル'。スキャンカウント0、論理読み取り0、物理読み取り0、先読み読み取り0、lob論理読み取り0、lob物理読み取り0、lob先読み読み取り0。表'ワークテーブル'。スキャンカウント4、論理読み取り167426、物理読み取り0、先読み読み取り0、lob論理読み取り0、lob物理読み取り0、lob先読み読み取り0。CPU時間=342ミリ秒、経過時間=233ミリ秒。
>結果をループして小さなバッチで更新するには:
declare @rowcount int = 1;
declare @batch_size int = 1000;
while @rowcount > 0
begin
update top(@batch_size) t set t.status_val = 'already updated'
from (
select *, row_number() over(partition by object_id order by (select null)) row_num
from foo
where status_val <> 'already updated'
) t
where row_num > 1
set @rowcount = @@rowcount;
end
これは、他の同時セッションがこのテーブルにアクセスしようとしている場合にロックダウンを維持するのに役立ちます。