Datenbankinterview: Slow by Slow

Wenn man statt einer einzigen Datenbankabfrage viele kleine Statements absetzt, ähnelt das direkt einem Interview. Fragen über Fragen.

Im Allgemeinen versucht man mit einer Abfrage das Problem möglichst umfassend zu erledigen. Sind also 500 Datensätze zu aktualisieren schreibt man ein einziges statt 500 Update Statements. Hier auch ein wunderbarer Blog Eintrag zu genau diesem „Slow by Slow“ Thema. Und was wenn das einzige Statement nicht möglich ist ? z.B. wenn das Problem nur iterativ/rekursiv zu lösen ist?

Ich bin auf diesen schon etwas älteren Blog Eintrag von Tom Kyte gestossen, weil mein eigenes Problem ähnlich strukturiert war. Jeder Schritt der Logik baute auf dem Ergebnis des letzten Schrittes auf. Es galt also auf andere Weise schneller zu werden.

for i in 0..500
    update test_tab set .....;
    commit;
end

Der Code wie er ist lief in meinem Setting ca. 220 Sekunden.

Die erste Verbesserung könnte sein, nicht mehr nach jedem Satz, sondern am Ende der Verarbeitung (ausserhalb der Schleife) den commit abzusetzen. Der Nachteil ist, dass parallel laufende Sessions die Änderungen bei langen Verarbeitungsläufen nicht oder nur sehr verspätet mitbekommen. In meinem Test würde das die Zeit sofort auf ca. 130 Sekunden reduzieren.

Eine andere Art ist Einfluss auf das Verhalten des Commits einzuwirken. Die entsprechenden Parameter sind „Commit_Write“ sowie „Commit_Logging“.

Der Default der Parameter ist „immediate“ sowie „wait“. Jedes Statement wartet also bis die Redo Informationen geschrieben sind – der Programmfluss ist solange unterbrochen.

Werden die Parameter auf „batch“ sowie „nowait“ gestellt wird diese Zeit eingespart. Auf der Strecke bleibt dabei die Transaktionssicherheit und ein im Fehlerfall ergibt sich ein undefinierter Zustand der Daten. Es empfiehlt sich also ein spärlicher Einsatz. Denkbar wäre das bei Migrationen oder länger laufenden ETL-Jobs die problemlos nachgestartet werden können.

Die Parameter lassen sich auf mehreren Ebenen permanent oder nicht permanent setzen. Mein Favorit ist in der Session –  so wird nichts anderes beeinflusst.

-- Aktivieren
alter session set commit_wait = nowait;
alter session set commit_logging = batch;

--Deaktivieren
alter session set commit_wait = wait;
alter session set commit_logging = immediate;

In meinem Testszenario werden damit aus 220 Sekunden 190 – ca. 15% Ersparnis. Nur durch das Setzen der Parameter.

Dieser Beitrag wurde unter Oracle veröffentlicht. Setze ein Lesezeichen auf den Permalink.