U kunt dit probleem oplossen zonder een join, wat betekent dat het betere prestaties zou moeten hebben. Het idee is om de gegevens te groeperen op uw object_id, waarbij het rijnummer van elke object_id wordt geteld. Dit is wat "partitioneren door" doet. Vervolgens kunt u bijwerken waar het rijnummer> 1 is. Hiermee worden alle dubbele object-id's bijgewerkt, behalve de eerste!
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
Op een testtabel van 82944 records was de prestatie zo (je kilometerstand kan variëren!):Tabel 'test'. Scantelling 5, logische leest 82283, fysieke leest 0, read-ahead leest 0, lob logische leest 0, lob fysieke leest 0, lob read-ahead leest 0.CPU-tijd =141 ms, verstreken tijd =150 ms.
We kunnen dit probleem zeker ook oplossen door een inner join te gebruiken, maar in het algemeen zou dit moeten leiden tot meer logische reads en hogere CPU:
Tabel 'test'. Scan count 10, logische leest 83622, fysieke leest 0, read-ahead leest 0, lob logische leest 0, lob fysieke leest 0, lob read-ahead leest 0.Tabel 'Werkbestand'. Scan count 0, logische leest 0, fysieke leest 0, read-ahead leest 0, lob logische leest 0, lob fysieke leest 0, lob read-ahead leest 0. Tabel 'Werktafel'. Scantelling 4, logische leest 167426, fysieke leest 0, read-ahead leest 0, lob logische leest 0, lob fysieke leest 0, lob read-ahead leest 0.CPU-tijd =342 ms, verstreken tijd =233 ms.
Om de resultaten te herhalen en in kleinere batches bij te werken:
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
Dit zal helpen om te blijven vergrendelen als andere gelijktijdige sessies toegang proberen te krijgen tot deze tabel.