Sie können dieses Problem ohne einen Join lösen, was bedeutet, dass es eine bessere Leistung haben sollte. Die Idee ist, die Daten nach Ihrer Objekt-ID zu gruppieren und die Zeilennummer jeder Objekt-ID zu zählen. Das macht "partition by". Dann können Sie aktualisieren, wo row_num> 1 ist. Dadurch werden alle duplizierten object_id außer der ersten aktualisiert!
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
Auf einer Testtabelle mit 82944 Datensätzen war die Leistung so (Ihre Laufleistung kann variieren!):Tabelle 'test'. Scan-Zähler 5, logische Lesevorgänge 82283, physische Lesevorgänge 0, Read-Ahead-Lesevorgänge 0, Lob-Logik-Reads 0, Lob-Physische Lesevorgänge 0, Lob-Read-Ahead-Lesevorgänge 0.CPU-Zeit =141 ms, verstrichene Zeit =150 ms.
Wir können dieses Problem sicherlich auch lösen, indem wir einen Inner Join verwenden, aber im Allgemeinen sollte dies zu mehr logischen Lesevorgängen und einer höheren CPU führen:
Tabelle 'Test'. Anzahl der Scans 10, logische Lesevorgänge 83622, physische Lesevorgänge 0, Read-Ahead-Lesevorgänge 0, logische Lob-Reads 0, physische Lob-Reads 0, Lob-Read-Ahead-Lesevorgänge 0.Tabelle „Arbeitsdatei“. Scan-Anzahl 0, logische Lesevorgänge 0, physische Lesevorgänge 0, Read-Ahead-Lesevorgänge 0, Lob-Logik-Reads 0, Lob-Physical-Reads 0, Lob-Read-Ahead-Reads 0. Tabelle „Arbeitstabelle“. Scan-Anzahl 4, logische Lesevorgänge 167426, physische Lesevorgänge 0, Read-Ahead-Lesevorgänge 0, Lob-Logik-Reads 0, Lob-Physische Lesevorgänge 0, Lob-Read-Ahead-Lesevorgänge 0.CPU-Zeit =342 ms, verstrichene Zeit =233 ms.
Um die Ergebnisse zu durchlaufen und in kleineren Stapeln zu aktualisieren:
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
Dies hilft dabei, die Sperrung aufrechtzuerhalten, wenn andere gleichzeitige Sitzungen versuchen, auf diese Tabelle zuzugreifen.