Temporäre Tabellen sind dank Caching und asynchroner E/A effektiv mit In-Memory-Tabellen identisch, und die Lösung für temporäre Tabellen erfordert keinen Overhead für die Konvertierung zwischen SQL und PL/SQL.
Bestätigung der Ergebnisse
Beim Vergleich der beiden Versionen mit RunStats sieht die temporäre Tabellenversion aus viel schlimmer. All dieser Müll für die temporäre Tabellenversion in Run1 und nur ein wenig zusätzlicher Speicher für die PL/SQL-Version in Run2. Auf den ersten Blick scheint PL/SQL der klare Sieger zu sein.
Type Name Run1 (temp) Run2 (PLSQL) Diff
----- -------------------------------- ------------ ------------ ------------
...
STAT physical read bytes 81,920 0 -81,920
STAT physical read total bytes 81,920 0 -81,920
LATCH cache buffers chains 104,663 462 -104,201
STAT session uga memory 445,488 681,016 235,528
STAT KTFB alloc space (block) 2,097,152 0 -2,097,152
STAT undo change vector size 2,350,188 0 -2,350,188
STAT redo size 2,804,516 0 -2,804,516
STAT temp space allocated (bytes) 12,582,912 0 -12,582,912
STAT table scan rows gotten 15,499,845 0 -15,499,845
STAT session pga memory 196,608 19,857,408 19,660,800
STAT logical read bytes from cache 299,958,272 0 -299,958,272
Aber am Ende des Tages zählt nur die Wanduhrzeit. Sowohl das Laden als auch das Abfragen laufen mit temporären Tabellen viel schneller ab.
Die PL/SQL-Version kann verbessert werden, indem BULK COLLECT
ersetzt wird mit cast(collect(test_o(MOD(a, 10), '' || MOD(a, 12))) as test_t) INTO t
. Aber es ist immer noch deutlich langsamer als die temporäre Tabellenversion.
Optimierte Lesevorgänge
Das Lesen aus der kleinen temporären Tabelle verwendet nur den Puffercache, der sich im Arbeitsspeicher befindet. Führen Sie nur den Abfrageteil viele Male aus und beobachten Sie, wie der consistent gets from cache
(Speicher) erhöhen, während der physical reads cache
(Festplatte) bleiben gleich.
select name, value
from v$sysstat
where name in ('db block gets from cache', 'consistent gets from cache',
'physical reads cache');
Optimierte Schreibvorgänge
Idealerweise gäbe es keine physischen I/Os, besonders da die temporäre Tabelle ON COMMIT DELETE ROWS
ist . Und es hört sich so an, als ob die nächste Version von Oracle einen solchen Mechanismus einführen könnte. Aber es spielt in diesem Fall keine große Rolle, die Festplatten-E/A scheint die Dinge nicht zu verlangsamen.
Führen Sie den Ladeschritt mehrmals aus und führen Sie dann select * from v$active_session_history order by sample_time desc;
aus . Die meisten I/Os sind BACKGROUND
, was bedeutet, dass nichts darauf wartet. Ich gehe davon aus, dass die interne Logik der temporären Tabelle nur eine Kopie der regulären DML-Mechanismen ist. Im Allgemeinen können neue Tabellendaten darf müssen auf die Festplatte geschrieben werden, wenn sie festgeschrieben ist. Oracle kann damit beginnen, daran zu arbeiten, beispielsweise indem es Daten aus dem Protokollpuffer auf die Festplatte verschiebt, aber es gibt keine Eile, bis es ein tatsächliches COMMIT
gibt .
Wo bleibt die PL/SQL-Zeit?
Ich habe keine Ahnung. Gibt es mehrere Kontextwechsel oder eine einzelne Konvertierung zwischen den SQL- und PL/SQL-Engines? Soweit ich weiß, zeigt keine der verfügbaren Metriken die Zeit Ausgaben für den Wechsel zwischen SQL und PL/SQL.
Wir werden vielleicht nie genau wissen, warum PL/SQL-Code langsamer ist. Ich mache mir darüber keine allzu großen Sorgen. Die allgemeine Antwort ist, dass die überwiegende Mehrheit der Datenbankarbeit sowieso in SQL erledigt werden muss. Es würde sehr viel Sinn machen, wenn Oracle mehr Zeit damit verbringen würde, den Kern ihrer Datenbank, SQL, zu optimieren, als die Add-on-Sprache, PL/SQL.
Zusätzliche Hinweise
Für Leistungstests kann es hilfreich sein, den connect by
zu entfernen Logik in einen separaten Schritt. Dieses SQL ist ein großartiger Trick zum Laden von Daten, aber es kann sehr langsam und ressourcenintensiv sein. Es ist realistischer, mit diesem Trick eine Beispieltabelle einmal zu laden und dann aus dieser Tabelle einzufügen.
Ich habe versucht, die neue Oracle 12c-Funktion, temporäres Rückgängigmachen, und die neue 18c-Funktion, private temporäre Tabellen, zu verwenden. Keine von beiden verbesserte die Leistung gegenüber regulären temporären Tabellen.
Ich würde nicht darauf wetten, aber ich sehe eine Möglichkeit, dass sich die Ergebnisse mit zunehmender Datenmenge vollständig ändern würden. Der Protokollpuffer und der Puffercache können nur so groß werden. Und schließlich könnte sich diese Hintergrund-E/A summieren und einige Prozesse überwältigen, was den BACKGROUND
umdreht warte in einen FOREGROUND
warte ab. Andererseits gibt es für die PL/SQL-Lösung nur so viel PGA-Speicher, und dann stürzt die Sache ab.
Letztendlich bestätigt dies teilweise meine Skepsis gegenüber "In-Memory-Datenbanken". Caching ist nichts Neues, Datenbanken tun es seit Jahrzehnten.