Le tabelle temporanee sono effettivamente le stesse delle tabelle in memoria grazie alla memorizzazione nella cache e all'I/O asincrono e la soluzione delle tabelle temporanee non richiede alcun sovraccarico per la conversione tra SQL e PL/SQL.
Conferma dei risultati
Confrontando le due versioni con RunStats, la versione della tabella temporanea sembra molto peggio. Tutta quella spazzatura per la versione della tabella temporanea in Run1 e solo un po' di memoria extra per la versione PL/SQL in Run2. All'inizio sembra che PL/SQL dovrebbe essere il chiaro vincitore.
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
Ma alla fine della giornata conta solo l'ora dell'orologio da parete. Sia il caricamento che i passaggi di query vengono eseguiti molto più velocemente con le tabelle temporanee.
La versione PL/SQL può essere migliorata sostituendo BULK COLLECT
con cast(collect(test_o(MOD(a, 10), '' || MOD(a, 12))) as test_t) INTO t
. Ma è ancora significativamente più lento della versione con tabella temporanea.
Letture ottimizzate
La lettura dalla piccola tabella temporanea utilizza solo la cache del buffer, che è in memoria. Esegui molte volte solo la parte della query e osserva come il consistent gets from cache
(memoria) aumenta mentre la physical reads cache
(disco) rimane lo stesso.
select name, value
from v$sysstat
where name in ('db block gets from cache', 'consistent gets from cache',
'physical reads cache');
Scritture ottimizzate
Idealmente non ci sarebbe I/O fisico, soprattutto perché la tabella temporanea è ON COMMIT DELETE ROWS
. E sembra che la prossima versione di Oracle possa introdurre un tale meccanismo. Ma non importa molto in questo caso, l'I/O del disco non sembra rallentare le cose.
Esegui il passaggio di caricamento più volte, quindi esegui select * from v$active_session_history order by sample_time desc;
. La maggior parte dell'I/O è BACKGROUND
, il che significa che nulla lo sta aspettando. Presumo che la logica interna della tabella temporanea sia solo una copia dei normali meccanismi DML. In generale, i nuovi dati della tabella possono deve essere scritto su disco, se è stato eseguito il commit. Oracle potrebbe iniziare a lavorarci, ad esempio spostando i dati dal buffer di registro al disco, ma non c'è fretta finché non si verifica un vero COMMIT
.
Dove va il tempo PL/SQL?
Non ho idea. Esistono più cambi di contesto o un'unica conversione tra i motori SQL e PL/SQL? Per quanto ne so, nessuna delle metriche disponibili mostra il tempo speso per passare da SQL a PL/SQL.
Potremmo non sapere mai esattamente perché il codice PL/SQL è più lento. Non me ne preoccupo troppo. La risposta generale è che la stragrande maggioranza del lavoro sul database deve comunque essere eseguita in SQL. Avrebbe molto senso se Oracle dedicasse più tempo all'ottimizzazione del core del proprio database, SQL, rispetto al linguaggio aggiuntivo, PL/SQL.
Note aggiuntive
Per i test delle prestazioni può essere utile rimuovere connect by
logica in un passaggio separato. Quell'SQL è un ottimo trucco per caricare i dati, ma può essere molto lento e dispendioso in termini di risorse. È più realistico caricare una tabella di esempio una volta con quel trucco, quindi inserirla da quella tabella.
Ho provato a utilizzare la nuova funzionalità Oracle 12c, annullamento temporaneo e la nuova funzionalità 18c, tabelle temporanee private. Nessuno dei due ha migliorato le prestazioni rispetto alle normali tabelle temporanee.
Non ci scommetterei, ma posso vedere un modo in cui i risultati cambierebbero completamente man mano che i dati diventano più grandi. Il buffer di registro e la cache del buffer possono solo diventare così grandi. E alla fine quell'I/O in background potrebbe sommarsi e sovraccaricare alcuni processi, trasformando il BACKGROUND
attendi in un FOREGROUND
aspettare. D'altra parte, c'è solo così tanta memoria PGA per la soluzione PL/SQL e poi le cose vanno in crash.
Infine, ciò conferma in parte il mio scetticismo nei confronti dei "database in memoria". La memorizzazione nella cache non è una novità, i database lo fanno da decenni.