Du kan løse dette problem uden en join, hvilket betyder, at det burde have bedre ydeevne. Ideen er at gruppere dataene efter dit object_id, og tælle rækkenummeret for hvert object_id. Dette er hvad "partition by" gør. Derefter kan du opdatere hvor rækken_numre er> 1. Dette vil opdatere alle duplikerede objekt_id undtagen den første!
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 testtabel med 82944 poster var ydeevnen sådan (din kilometertal kan variere!):Tabel 'test'. Scanning tæller 5, logisk læser 82283, fysisk læser 0, read-ahead læser 0, lob logisk læser 0, lob fysisk læser 0, lob read-ahead læser 0.CPU tid =141 ms, forløbet tid =150 ms.
Vi kan bestemt også løse dette problem ved at bruge en indre joinforbindelse, men generelt burde dette føre til mere logiske læsninger og højere CPU:
Tabel 'test'. Scanningsantal 10, logisk læser 83622, fysisk læser 0, read-ahead læser 0, lob logisk læser 0, lob fysisk læser 0, lob read-ahead læser 0. Tabel 'Workfile'. Scanningsantal 0, logisk læser 0, fysisk læser 0, read-ahead læser 0, lob logisk læser 0, lob fysisk læser 0, lob read-ahead læser 0.Tabel 'Arbejdstabel'. Scanning tæller 4, logisk læser 167426, fysisk læser 0, read-ahead læser 0, lob logisk læser 0, lob fysisk læser 0, lob read-ahead læser 0.CPU tid =342 ms, forløbet tid =233 ms.
Sådan går du over resultaterne og opdaterer i mindre partier:
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
Dette vil hjælpe med at blive ved med at låse ned, hvis andre samtidige sessioner forsøger at få adgang til denne tabel.