Du kan lösa det här problemet utan en join, vilket betyder att det borde ha bättre prestanda. Tanken är att gruppera data efter ditt object_id, och räkna radnumret för varje object_id. Detta är vad "partition by" gör. Sedan kan du uppdatera var row_num är> 1. Detta kommer att uppdatera alla duplicerade object_id utom det första!
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
På en testtabell med 82944 poster var prestandan sådan (din körsträcka kan variera!):Tabell 'test'. Skanningsantal 5, logiskt läser 82283, fysiskt läser 0, read-ahead läser 0, lob logiskt läser 0, lob fysisk läser 0, lob läser framåt läser 0. CPU-tid =141 ms, förfluten tid =150 ms.
Vi kan säkert också lösa detta problem genom att använda en inre koppling, men i allmänhet borde detta leda till mer logiska läsningar och högre CPU:
Tabell 'test'. Scan count 10, logiskt läser 83622, fysiskt läser 0, read-ahead läser 0, lob logiskt läser 0, lob fysisk läser 0, lob läser framåt läser 0. Tabell 'Arbetsfil'. Scan count 0, logiskt läser 0, fysiskt läser 0, read-ahead läser 0, lob logiskt läser 0, lob fysisk läser 0, lob read-ahead läser 0. Tabell 'Arbetstabell'. Scan count 4, logiskt läser 167426, fysiskt läser 0, read-ahead läser 0, lob logiskt läser 0, lob fysisk läser 0, lob läser framåt läser 0. CPU-tid =342 ms, förfluten tid =233 ms.
Så här går du igenom resultaten och uppdaterar i mindre omgångar:
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
Detta hjälper till att fortsätta låsa om andra samtidiga sessioner försöker komma åt den här tabellen.