Sqlserver
 sql >> Baza danych >  >> RDS >> Sqlserver

Zaktualizuj wszystkie zduplikowane rekordy z wyjątkiem jednego w tabeli w SQL Server

Możesz rozwiązać ten problem bez sprzężenia, co oznacza, że ​​powinien mieć lepszą wydajność. Chodzi o to, aby pogrupować dane według identyfikatora object_id, licząc numer wiersza każdego identyfikatora object_id. To właśnie robi "partycjonowanie przez". Następnie możesz zaktualizować, gdzie row_num jest> 1. Spowoduje to aktualizację wszystkich zduplikowanych identyfikatorów_obiektów z wyjątkiem pierwszego!

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 

Na stole testowym 82944 rekordów wydajność była taka (Twój przebieg może się różnić!):Tabela „test”. Liczba skanów 5, odczyty logiczne 82283, odczyty fizyczne 0, odczyty z wyprzedzeniem 0, odczyty logiczne lobu 0, odczyty fizyczne lobu 0, odczyty z wyprzedzeniem lobu 0. Czas procesora =141 ms, czas, który upłynął =150 ms.

Z pewnością możemy również rozwiązać ten problem za pomocą sprzężenia wewnętrznego, jednak generalnie powinno to prowadzić do większej liczby logicznych odczytów i większego procesora:

Tabela „test”. Liczba skanów 10, odczyty logiczne 83622, odczyty fizyczne 0, odczyty z wyprzedzeniem 0, odczyty logiczne lob 0, odczyty fizyczne lob 0, odczyty z wyprzedzeniem lob 0. Tabela „Plik roboczy”. Liczba skanów 0, odczyty logiczne 0, odczyty fizyczne 0, odczyty z wyprzedzeniem 0, odczyty logiczne LOB 0, odczyty fizyczne LOB 0, odczyty z wyprzedzeniem LOB 0. Tabela „Tabela robocza”. Liczba skanów 4, odczyty logiczne 167426, odczyty fizyczne 0, odczyty z wyprzedzeniem 0, odczyty logiczne lobu 0, odczyty fizyczne lobu 0, odczyty z wyprzedzeniem lobu 0. Czas procesora =342 ms, czas, który upłynął =233 ms.

Aby przeglądać wyniki i aktualizować je w mniejszych partiach:

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

Pomoże to utrzymać blokowanie, jeśli inne współbieżne sesje próbują uzyskać dostęp do tej tabeli.



  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Jak mogę powiadomić mój program o aktualizacji bazy danych?

  2. Jak utworzyć ograniczenie sprawdzania w pojedynczej kolumnie w SQL Server — samouczek SQL Server/TSQL — część 83

  3. Składnia pętli for w SQL Server

  4. Naśladuj group_concat() w połączeniu z GROUP BY

  5. Jak zachować kolejność wstawiania w SQL Server