Samstag, Januar 18, 2014

Schnelle Datensatz-Generierung

Im OTN Forum hat sich dieser Tage ein Thread mit einer recht interessanten Diskussion zum Thema der schnellsten Möglichkeit zur Erzeugung einer großen Mengen von Test-Datensätzen ergeben. Ausgangspunkt war, dass der Fragesteller des Threads mit der Performance eines INSERT mit einer connect by level Generierung von 10 Millionen Datensätzen nicht zufrieden war und nach schnelleren Optionen suchte. David Berger schlug eine PL/SQL-Lösung mit Collections und Bulk Insert vor, die tatsächlich im System des OP zu einer deutlichen Beschleunigung führte, und erklärte "There are cases where the PL/SQL can be faster then a pure SQL". Obwohl ich der Meinung bin, dass SQL fast immer die schnellere Lösung liefert, will ich der Aussage nicht grundsätzlich widersprechen, da man entsprechende Fälle gewiss konstruieren kann, hatte aber die Vermutung, dass im gegebenen Fall auch schnelle SQL-Lösungen möglich sein sollten und die schlechte Performance der connect by level Variante auf der Größe der Level-Angabe beruhte - entsprechend der Ausführungen von Tanel Poder, der vor einigen Jahren auf die großen UGA-Belastungen durch die massiven Rekursionen hinwies und alternativ eine Lösung mit einem cartesischen Produkt kleiner Generator-Queries vorschlug. Diese Variante brachte im System des OP allerdings nur eine geringfügige Beschleunigung, was mich wunderte und Jonathan Lewis dazu brachte, das Thema genauer zu untersuchen. Später hat dann auch Randolf Geist zusätzliche Informationen beigesteuert. Hier folgen ein paar Punkte, die mir besonders erinnerungswürdig scheinen:
  • die PL/SQL-Lösung skaliert nicht, da sie den Aufbau der kompletten Ergebnismenge im Speicher erfordert, während die Speichernutzung der SQL-Variante mit cartesian joins moderat bleibt.
  • die im Testszenario des OP verwendete dbms_random-Funktion verursachte bei Jonathan Lewis ca. 85% der Laufzeit, weshalb er eine Parallelisierung des Funktionsaufruf vorschlug (oder auch den Verzicht auf den Aufruf und die Verwenung von rownum).
  • eine Parallelisierung der PL/SQL-Lösung wäre über ein Splitting der ursprünglichen Prozedur in mehrere Teile möglich, die jeweils bestimmte Datenbereiche abarbeiten. Entscheidend ist dabei, dass es nicht darum geht, das INSERT zu parallelisieren, sondern den teuren Funktionsaufruf.
  • bei der Parallelisierung der Funktionsaufrufe ist (natürlich) die Anzahl der CPUs entscheidend.
  • die Verwendung von ROWNUM scheint einen Bug bei der Parallelisierung hervorzurufen. Durch Vermeidung der Pseudo-Column konnte Randolf Geist die tatsächliche Parallelisierung der Operation deutlich verbessern.
  • Zur den Performance-Vorteilen von PL/SQL zu SQL auf seiner Workstation schreibt Jonathan Lewis: "My guess about the PL/SQL running faster (on my machine, at any rate) is that it's a measure of the inter-process communication costs of VMWare which appears in the SQL but doesn't appear when I run two independent serial processes for the pl/sql."
Sollte der Thread noch weitere interessante Details hervorbringen, werde ich sie ergänzen.

Keine Kommentare:

Kommentar veröffentlichen