2012-04-03 8 views
2

ich redundanten Zeilen aus einer SQL-Tabelle, [InfoBucket], mit Spalten zu entfernen bin versucht:Optimierung der Entfernung von SQL Duplikaten mit ROW_NUMBER

[ID] (varchar(16)), [column1], ... [columnN], [Speed] (bigint) 

([column1 ... N] sind Datentypen aus ganzen Zahlen im Bereich an varchar() - Objekte unterschiedlicher Länge.)

Es gibt Zeilen in der Tabelle, die in den [ID] - und einigen [column1 ... N] -Spalten den gleichen Wert haben. Ich nehme alle diese Duplikate und lösche alle außer der Zeile, die die größte [Geschwindigkeit] hat.

Es gibt ungefähr 400 Millionen Zeilen im [InfoBucket].

die Arbeit in überschaubare Einheiten zu spalten, ich habe eine andere Tabelle, [UniqueIDs], mit einer Spalte:

[ID] (varchar (16))

und die wie so bevölkert ist:

begin 

insert into [UniqueIDs] 

select distinct [ID] from [InfoBucket] 

end 

go 

Es gibt ungefähr 15 Millionen Zeilen in [UniqueIDs].

Ich habe mit Martin Smiths ausgezeichnete Antwort mit auf eine similar question:

Mein Verfahren, das derzeit wie folgt aussieht:

begin 

declare @numIDs int 

set @numIDs = 10000 

;with toRemove as 
(

select ROW_NUMBER over (partition by 

[ID], 
[column1], 
... 
[columnN] 

order by [Speed] desc) as 'RowNum' 

from [InfoBucket] 

where [ID] in 
(

select top (@numIDs) [ID] from [UniqueIDs] order by [ID] 

) 

) 

delete toRemove 

where RowNum > 1 

option (maxdop 1) 

; 

;with IDsToRemove as 
(

select top (@numIDs) [ID] from [UniqueIDs] order by [ID] 

) 

delete IDsToRemove 

option (maxdop 1) 

end 

go 

Es gibt nicht gruppierte Indizes auf [ID] sowohl in [InfoBucket] und [UniqueIDs], und die " partition by ... "in der over-Klausel enthält nur die Spalten, die verglichen werden müssen.

Jetzt ist mein Problem, dass es etwas mehr als sechs Minuten dauert, damit dieser Vorgang ausgeführt wird. Wenn der Wert @numIDs eingestellt wird, ändert sich die Laufzeit linear (dh wenn @numIDs den Wert 1000 hat, läuft der Vorgang etwa 36 Sekunden (6 Minuten/10) und wenn @numIDs den Wert 1.000.000 hat, läuft der Vorgang ungefähr ab 10 Stunden (6 min * 100.), was bedeutet, dass alle Duplikate zu entfernen in [InfoBucket] Tage dauert

habe ich versucht, das Hinzufügen einer uniqueidentifier Spalte [UI_ID] zu [InfoBucket] und einen gruppierten Index auf sie zu schaffen (so [InfoBucket] hatte. Ein Clustered - Index auf [UI_ID] und ein Nonclustered auf [ID]), aber das hat die Laufzeit tatsächlich erhöht.

Gibt es eine Möglichkeit, das weiter zu optimieren?

Antwort

0

Der Schlüssel ist, den Sweetspot zum Löschen der Zeilen zu finden. Spielen Sie mit @numIds, um das schnellste Inkrement zu finden, und lassen Sie es dann ablaufen.

Es ist 400 Millionen Zeilen, es wird nicht den gesamten Prozess in Minuten, vielleicht Stunden, es wird Zeit brauchen. Solange die Tabelle nicht schneller füllt, können Sie die Duplikate entfernen, Sie sind in Ordnung.

Finden Sie den Sweet Spot, und planen Sie ihn dann so, dass er häufig und außerhalb des Maximums läuft. Dann überprüfen Sie den Prozess von Zeit zu Zeit, um sicherzustellen, dass der Sweet Spot süß bleibt.

Die einzige andere Sache, die ich denken kann, ist, die Dupes außerhalb des Löschens zu berechnen. Dies wird einige Zeit sparen.Insbesondere, wenn Sie die Duplikate in einer SQL-Anweisung berechnen können, dann fügen Sie diese Daten in eine andere Tabelle ein (zB DupeIdsToDelete, dann führen Sie eine Löschschleife für diese IDs aus)