verwendetes Datenbanksystem: SqlServer
Ich hab eine komplizierte Abfrage, die läuft recht lange und löscht recht viel.
Der Db-Admin wünscht, dass die Löscherei in Chunks von 500 Datensätzen erfolgt.
Da habich eine komplizierte Lösung, wo ich erst nachzähle, wieviele denn gelöscht werden, dann die Anzahl der dafür benötigten Chunks, und dann in einer While-Schleife abfahren.
Etwas einfacher, aber iwie auch skurril ist eine Lösung, wo ich das Output-Feature dazu nutze, herauszubekommen, wieviele Datensätze gelöscht wurden, und wenn weniger als ChunkSize, die Schleife verlassen - beispielCode (b.Bed auskopieren + testen):
--Chunken mit dem Output-Feature
create table #todelete(numb int )
create table #todelete2(numb int )
declare @count int=0
while @count<100
Begin
insert into #todelete values(@count)
insert into #todelete2 values(@count*2)
select @count=@count+1
end
declare @ChunkSize1 int = 15
create table #deleteds(numb int )
declare @delCount int = @ChunkSize1
while @delCount = @ChunkSize1
Begin
Begin TRANSACTION;
Delete Top (@ChunkSize1) td
output 1 as numb into #deleteds
FROM #todelete td
join #todelete2 td2 on td.numb=td2.numb
COMMIT TRANSACTION;
select @delCount= count(*) from #deleteds;
select @delCount
truncate table #deleteds;
End
select count(*) Rest from #todelete;
drop table #deleteds
drop table #todelete
drop table #todelete2
(das mit toDelete, toDelete2 soll andeuten, dass die Abfrage komplex ist)
Meine Frage: Gibts da nicht was einfacheres?
Der frühe Apfel fängt den Wurm.
Sieht schon etwas kompliziert aus. Eine leere Zuweisung an select @delCount ?
Sieh dir mal @@ROWCOUNT an. Das sollte auf die Anzahl der Zeilen gesetzt werden die soeben gelöscht wurden.
Wie viele Datensätze sind es denn im Normalfall? Ich würde mit dem Admin klären warum es nur 500 pro Vorgang sein sollen. Mit dem ganzen Overhead und ständigem neu joinen von Datensätzen machst du eventuell mehr Performance kaputt als wenn du einfach am Stück ein paar tausend Datensätze auf einmal löschst.
Ich nutze für 'Chunk' Operation immer dieses Skript:
WHILE ( 1 = 1 )
BEGIN
BEGIN TRANSACTION;
DELETE TOP ( 500 )
FROM dbo.table1
WHERE condition IS NULL;
IF @@ROWCOUNT = 0 -- terminating condition;
BEGIN
COMMIT TRANSACTION;
BREAK;
END;
COMMIT TRANSACTION;
END;
Die Anzahl der Rows ist natürlich immer situationsabhängig.
Musst du Millionen von Datensätzen löschen, würde es mit 500 länger dauern, als wenn du z.B. 10000 auf einmal löscht.
Generell solltest aber das machen was dein DBA dir vorgibt. Vorausgesetzt er kennt sich aus 😉
Vorausgesetzt er kennt sich aus
Exakt das wollte ich mit meinem Tip sicherstellen 😉
Der Gedanke "oh das dauert sicher lange, mach lieber mal in kleinen Schritten" kommt auch EDV-nahen Personen, die unter anderem einen Datenbankserver mit verwalten (müssen) und sich aber nicht so richtig auskennen. Daher lieber doch mal nachfragen.
Wichtig ist auch Performancetests zu machen. Am besten immer wieder loggen wie lange etwas dauert und bei Bedarf eingreifen.
Und immer dran denken: wenn die DB lahm ist kriegt der es ab der sie programmiert hat, nicht der von dem Tips kamen.
Übrigens kann man natürlich nicht nur zu kleine Schritte machen sondern auch zu große. Immer alles auf einmal tun wollen kann dazu führen dass ein Logfile überläuft. Je nach DB und Einstellungen. Es kommt immer drauf an...