As tabelas temporárias são efetivamente iguais às tabelas na memória graças ao armazenamento em cache e E/S assíncrona, e a solução de tabela temporária não requer nenhuma sobrecarga para a conversão entre SQL e PL/SQL.
Confirmar os resultados
Comparando as duas versões com RunStats, a versão da tabela temporária parece muito pior. Todo aquele lixo para a versão de tabela temporária em Run1, e apenas um pouco de memória extra para a versão PL/SQL em Run2. A princípio, parece que o PL/SQL deve ser o vencedor.
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
Mas, no final do dia, apenas a hora do relógio de parede importa. As etapas de carregamento e consulta são executadas muito mais rapidamente com tabelas temporárias.
A versão PL/SQL pode ser melhorada substituindo o
BULK COLLECT
com cast(collect(test_o(MOD(a, 10), '' || MOD(a, 12))) as test_t) INTO t
. Mas ainda é significativamente mais lento do que a versão de tabela temporária. Leituras otimizadas
A leitura da pequena tabela temporária usa apenas o cache do buffer, que está na memória. Execute apenas a parte da consulta várias vezes e observe como o
consistent gets from cache
(memória) aumentam enquanto o physical reads cache
(disco) permanecer o mesmo. select name, value
from v$sysstat
where name in ('db block gets from cache', 'consistent gets from cache',
'physical reads cache');
Gravações otimizadas
Idealmente, não haveria E/S física, especialmente porque a tabela temporária é
ON COMMIT DELETE ROWS
. E parece que a próxima versão do Oracle pode introduzir esse mecanismo. Mas não importa muito neste caso, a E/S do disco não parece desacelerar as coisas. Execute a etapa de carregamento várias vezes e, em seguida, execute
select * from v$active_session_history order by sample_time desc;
. A maior parte do I/O é BACKGROUND
, o que significa que nada está esperando por ele. Presumo que a lógica interna da tabela temporária seja apenas uma cópia dos mecanismos DML regulares. Em geral, novos dados de tabela podem precisa ser gravado em disco, se for confirmado. O Oracle pode começar a trabalhar nele, por exemplo, movendo dados do buffer de log para o disco, mas não há pressa até que haja um COMMIT
real . Para onde vai o tempo PL/SQL?
Eu não tenho idéia. Existem várias opções de contexto ou uma única conversão entre os mecanismos SQL e PL/SQL? Até onde sei, nenhuma das métricas disponíveis mostra o tempo gasto na alternância entre SQL e PL/SQL.
Talvez nunca saibamos exatamente por que o código PL/SQL é mais lento. Eu não me preocupo muito com isso. A resposta geral é que a grande maioria do trabalho de banco de dados precisa ser feito em SQL de qualquer maneira. Faria muito sentido se a Oracle gastasse mais tempo otimizando o núcleo de seu banco de dados, SQL, do que a linguagem complementar, PL/SQL.
Observações adicionais
Para testes de desempenho, pode ser útil remover o
connect by
lógica em uma etapa separada. Esse SQL é um ótimo truque para carregar dados, mas pode ser muito lento e consumir muitos recursos. É mais realista carregar uma tabela de amostra uma vez com esse truque e depois inserir dessa tabela. Tentei usar o novo recurso Oracle 12c, desfazer temporário, e o novo recurso 18c, tabelas temporárias privadas. Nenhum deles melhorou o desempenho em relação às tabelas temporárias regulares.
Eu não apostaria nisso, mas posso ver uma maneira de os resultados mudarem completamente à medida que os dados aumentam. O buffer de log e o cache de buffer só podem ficar tão grandes. E, eventualmente, essa E/S em segundo plano pode aumentar e sobrecarregar alguns processos, transformando o
BACKGROUND
aguarde em um FOREGROUND
esperar. Por outro lado, há tanta memória PGA para a solução PL/SQL, e então as coisas falham. Finalmente, isso confirma parcialmente meu ceticismo em relação aos "bancos de dados na memória". O armazenamento em cache não é novidade, os bancos de dados fazem isso há décadas.