web-dev-qa-db-fra.com

Quel est le moyen le plus rapide de supprimer des lignes en double?

J'ai besoin de supprimer des lignes en double d'une grande table. Quelle est la meilleure façon de réaliser cela?

actuellement, j'utilise cet algorithme:

declare @t table ([key] int  )

insert into @t select 1
insert into @t select 1
insert into @t select 1
insert into @t select 2
insert into @t select 2
insert into @t select 3
insert into @t select 4
insert into @t select 4
insert into @t select 4
insert into @t select 4
insert into @t select 4
insert into @t select 5
insert into @t select 5
insert into @t select 5
insert into @t select 5
insert into @t select 5
insert into @t select 6
insert into @t select 6
insert into @t select 6
insert into @t select 7
insert into @t select 7
insert into @t select 8
insert into @t select 8
insert into @t select 9
insert into @t select 9
insert into @t select 9
insert into @t select 9
insert into @t select 9


select * from @t

; with cte as (
    select *
        , row_number() over (partition by [Key] order by [Key]) as Picker
    from @t
    )
delete cte 
where Picker > 1

select * from @t

quand je l'exécute sur mon système:

;WITH Customer AS
    (
    SELECT *, ROW_NUMBER() OVER (PARTITION BY AccountCode ORDER BY AccountCode ) AS [Version]
    FROM Stage.Customer
    )
    DELETE
    FROM    Customer
    WHERE   [Version] <> 1

enter image description here

J'ai trouvé que <> 1 est meilleur que> 1.

Je pourrais créer cet index, actuellement pas présent:

USE [BodenDWH]
GO
CREATE NONCLUSTERED INDEX [<Name of Missing Index, sysname,>]
ON [Stage].[Customer] ([AccountCode])
INCLUDE ([ID])
GO

enter image description here

Y a-t-il une autre façon de faire cela?

À cette occasion, ce tableau n'est pas grand - environ 500 000 enregistrements sur le système en direct.

le Supprimer fait partie d'un package SSIS, il fonctionne quotidiennement et supprime environ 10-15 enregistrements par jour.

il y a des problèmes dans la manière dont les données sont structurées, j'ai juste besoin d'un code de compte pour chaque client, mais il pourrait y avoir des doublons et s'ils ne sont pas supprimés, ils brisent le colis sur une étape ultérieure.

Ce n'était pas moi qui a développé le paquet et ma portée n'est pas de ré-concevoir quoi que ce soit.

Je suis juste après la meilleure façon de vous débarrasser des duplicats, de la manière la plus rapide possible, sans avoir à vous référer à la création d'index, ni quoi que ce soit, juste le code T-SQL.

4
Marcello Miorelli

Si la table est petite et que le nombre de lignes que vous supprimez est faible, puis utilisez

;WITH Customer AS
    (
    SELECT *, ROW_NUMBER() OVER (PARTITION BY AccountCode ORDER BY (select null) ) AS [Version]
    FROM dbo.Customer
    )
    DELETE
    FROM    Customer
    WHERE   [Version] > 1;

Remarque: Dans la requête ci-dessus, vous utilisez une commande arbitraire dans la clause de commande de la fenêtre ORDER BY (select null) (appris de Livre de requête T-SQL de Itzik Ben-Gan et @aaronbertrand cité qui ci-dessus aussi) .

Si la table est grande (E.G. 5M enregistrements), supprimez IN petit nombre de lignes ou de morceaux aidera ne pas bloquer le journal des transactions et empêchera Serrure d'escalade .

Une escalade de verrouillage se produira si et uniquement si une instruction Transact-SQL a acquis au moins 5000 verrouillages sur une seule référence d'une table.

while 1=1
begin
WITH Customer AS
    (
    SELECT *, ROW_NUMBER() OVER (PARTITION BY AccountCode ORDER BY (select null) ) AS [Version]
    FROM dbo.Customer
    )
    DELETE top(4000) -- choose a lower batch size than 5000 to prevent lock escalation 
    FROM    Customer
    WHERE   [Version] > 1

    if @@ROWCOUNT < 4000
    BREAK ;

end
5
Kin Shah