Midlertidige tabeller er reelt de samme som tabeller i hukommelsen takket være caching og asynkron I/O, og den midlertidige tabelløsning kræver ingen overhead til konvertering mellem SQL og PL/SQL.
Bekræftelse af resultaterne
Sammenligner man de to versioner med RunStats, ser den midlertidige tabelversion ud meget værre. Alt det skrammel til den midlertidige tabelversion i Run1, og kun lidt ekstra hukommelse til PL/SQL-versionen i Run2. Umiddelbart ser det ud til, at PL/SQL burde være den klare vinder.
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 slutningen af dagen er det kun væguret, der betyder noget. Både indlæsnings- og forespørgselstrinene kører meget hurtigere med midlertidige tabeller.
PL/SQL-versionen kan forbedres ved at erstatte BULK COLLECT
med cast(collect(test_o(MOD(a, 10), '' || MOD(a, 12))) as test_t) INTO t
. Men den er stadig betydeligt langsommere end den midlertidige tabelversion.
Optimerede læsninger
Læsning fra den lille midlertidige tabel bruger kun buffercachen, som er i hukommelsen. Kør kun forespørgselsdelen mange gange, og se, hvordan consistent gets from cache
(hukommelse) øges, mens physical reads cache
(disk) forbliv den samme.
select name, value
from v$sysstat
where name in ('db block gets from cache', 'consistent gets from cache',
'physical reads cache');
Optimeret skrivning
Ideelt set ville der ikke være nogen fysisk I/O, især da den midlertidige tabel er ON COMMIT DELETE ROWS
. Og det lyder som om, at den næste version af Oracle måske introducerer en sådan mekanisme. Men det betyder ikke meget i dette tilfælde, disk I/O ser ikke ud til at bremse tingene.
Kør indlæsningstrinnet flere gange, og kør derefter select * from v$active_session_history order by sample_time desc;
. Det meste af I/O er BACKGROUND
, hvilket betyder, at intet venter på den. Jeg antager, at den midlertidige tabel interne logik kun er en kopi af almindelige DML-mekanismer. Generelt kan nye tabeldata skal skrives til disk, hvis det er begået. Oracle kan begynde at arbejde på det, for eksempel ved at flytte data fra logbufferen til disken, men der er ingen hast, før der er en faktisk COMMIT
.
Hvor bliver PL/SQL-tiden af?
Jeg har ingen anelse. Er der flere kontekstskift, eller en enkelt konvertering mellem SQL- og PL/SQL-motorerne? Så vidt jeg ved, viser ingen af de tilgængelige metrics tiden brugt på at skifte mellem SQL og PL/SQL.
Vi ved måske aldrig præcis, hvorfor PL/SQL-kode er langsommere. Jeg bekymrer mig ikke for meget om det. Det generelle svar er, at langt størstedelen af databasearbejdet skal udføres i SQL alligevel. Det ville give meget mening, hvis Oracle brugte mere tid på at optimere kernen af deres database, SQL, end tilføjelsessproget PL/SQL.
Yderligere bemærkninger
Til præstationstestning kan det være nyttigt at fjerne connect by
logik ind i et separat trin. Den SQL er et godt trick til at indlæse data, men det kan være meget langsomt og ressourcekrævende. Det er mere realistisk at indlæse en prøvetabel én gang med det trick og derefter indsætte fra den tabel.
Jeg prøvede at bruge den nye Oracle 12c-funktion, midlertidig fortryd, og den nye 18c-funktion, private midlertidige borde. Ingen af dem forbedrede ydeevnen i forhold til almindelige midlertidige tabeller.
Jeg ville ikke satse på det, men jeg kan se en måde, hvorpå resultaterne helt vil ændre sig, efterhånden som dataene bliver større. Logbufferen og buffercachen kan kun blive så stor. Og i sidste ende kunne den baggrunds-I/O tilføje op og overvælde nogle processer og vende BACKGROUND
vent ind i en FOREGROUND
vente. På den anden side er der kun så meget PGA-hukommelse til PL/SQL-løsningen, og så går tingene i stykker.
Endelig bekræfter dette delvist min skepsis over for "in-memory databaser". Caching er ikke noget nyt, databaser har gjort det i årtier.