Temporära tabeller är i praktiken desamma som tabeller i minnet tack vare cachning och asynkron I/O, och den temporära tabelllösningen kräver ingen overhead för konvertering mellan SQL och PL/SQL.
Bekräftar resultaten
Jämför man de två versionerna med RunStats, ser den temporära tabellversionen ut mycket värre. Allt skräp för den temporära tabellversionen i Run1, och bara lite extra minne för PL/SQL-versionen i Run2. Till en början verkar det som att PL/SQL borde vara den klara vinnaren.
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
Men i slutet av dagen är det bara väggklockans tid som spelar roll. Både laddnings- och frågesteget går mycket snabbare med tillfälliga tabeller.
PL/SQL-versionen kan förbättras genom att ersätta BULK COLLECT
med cast(collect(test_o(MOD(a, 10), '' || MOD(a, 12))) as test_t) INTO t
. Men den är fortfarande betydligt långsammare än den temporära tabellversionen.
Optimerade läsningar
Läsning från den lilla temporära tabellen använder bara buffertcachen, som finns i minnet. Kör bara frågedelen många gånger och se hur consistent gets from cache
(minne) ökar medan physical reads cache
(disk) förbli densamma.
select name, value
from v$sysstat
where name in ('db block gets from cache', 'consistent gets from cache',
'physical reads cache');
Optimerade skrivningar
Helst skulle det inte finnas någon fysisk I/O, särskilt eftersom den temporära tabellen är ON COMMIT DELETE ROWS
. Och det låter som att nästa version av Oracle kan introducera en sådan mekanism. Men det spelar inte så stor roll i det här fallet, disk I/O verkar inte sakta ner.
Kör laddningssteget flera gånger och kör sedan select * from v$active_session_history order by sample_time desc;
. Det mesta av I/O är BACKGROUND
, vilket betyder att ingenting väntar på den. Jag antar att den tillfälliga tabellens interna logik bara är en kopia av vanliga DML-mekanismer. I allmänhet kan ny tabelldata måste skrivas till disken, om den är committerad. Oracle kan börja arbeta med det, till exempel genom att flytta data från loggbufferten till disken, men det är ingen brådska förrän det finns en faktisk COMMIT
.
Var tar PL/SQL-tiden vägen?
Jag har ingen aning. Finns det flera kontextväxlar, eller en enda konvertering mellan SQL- och PL/SQL-motorerna? Såvitt jag vet visar ingen av de tillgängliga mätvärdena tiden spenderas på att växla mellan SQL och PL/SQL.
Vi kanske aldrig vet exakt varför PL/SQL-kod är långsammare. Jag oroar mig inte för mycket. Det allmänna svaret är att den stora majoriteten av databasarbetet måste göras i SQL ändå. Det skulle vara mycket vettigt om Oracle ägnade mer tid åt att optimera kärnan i sin databas, SQL, än tilläggsspråket PL/SQL.
Ytterligare anmärkningar
För prestandatestning kan det vara bra att ta bort connect by
logik i ett separat steg. Att SQL är ett bra knep för att ladda data, men det kan vara väldigt långsamt och resurskrävande. Det är mer realistiskt att ladda en exempeltabell en gång med det tricket och sedan infoga från den tabellen.
Jag försökte använda den nya Oracle 12c-funktionen, temporär ångra, och den nya 18c-funktionen, privata temporära tabeller. Ingen av dem förbättrade prestandan jämfört med vanliga temporära tabeller.
Jag skulle inte satsa på det, men jag kan se ett sätt att resultaten helt skulle förändras när data blir större. Loggbufferten och buffertcachen kan bara bli så stor. Och så småningom kan den bakgrunds-I/O lägga till och överväldiga vissa processer, vilket gör BACKGROUND
vänta in i en FOREGROUND
vänta. Å andra sidan finns det bara så mycket PGA-minne för PL/SQL-lösningen, och sedan kraschar saker.
Slutligen bekräftar detta delvis min skepsis mot "in-memory-databaser". Cachning är inget nytt, databaser har gjort det i decennier.