Altre risposte coprono abbastanza bene le differenze di sintassi, quindi non entrerò in quello. Invece questa risposta coprirà solo le prestazioni in Oracle.
L'ottimizzatore Oracle può scegliere di materializzare i risultati di un CTE in una tabella temporanea interna. Per farlo, utilizza un'euristica anziché un'ottimizzazione basata sui costi. L'euristica è qualcosa del tipo "Materializza il CTE se non è un'espressione banale e al CTE viene fatto riferimento più di una volta nella query". Ci sono alcune domande per le quali la materializzazione migliorerà le prestazioni. Ci sono alcune domande per le quali la materializzazione ridurrà drasticamente le prestazioni. L'esempio seguente è un po 'inventato ma illustra bene il punto:
Innanzitutto crea una tabella con una chiave primaria che contenga numeri interi compresi tra 1 e 10000:
CREATE TABLE N_10000 (NUM_ID INTEGER NOT NULL, PRIMARY KEY (NUM_ID));
INSERT /*+APPEND */ INTO N_10000
SELECT LEVEL
FROM DUAL
CONNECT BY LEVEL <= 10000
ORDER BY LEVEL;
COMMIT;
Considera la seguente query che utilizza due tabelle derivate:
SELECT t1.NUM_ID
FROM
(
SELECT n1.NUM_ID
FROM N_10000 n1
CROSS JOIN N_10000 n2
) t1
LEFT OUTER JOIN
(
SELECT n1.NUM_ID
FROM N_10000 n1
CROSS JOIN N_10000 n2
) t2 ON t1.NUM_ID = t2.NUM_ID
WHERE t1.NUM_ID <= 0;
Possiamo esaminare questa query e determinare rapidamente che non restituirà alcuna riga. Oracle dovrebbe essere in grado di utilizzare l'indice anche per determinarlo. Sulla mia macchina la query termina quasi istantaneamente con il seguente piano:
Non mi piace ripetermi, quindi proviamo la stessa query con un CTE:
WITH N_10000_CTE AS (
SELECT n1.NUM_ID
FROM N_10000 n1
CROSS JOIN N_10000 n2
)
SELECT t1.NUM_ID
FROM N_10000_CTE t1
LEFT JOIN N_10000_CTE t2 ON t1.NUM_ID = t2.NUM_ID
WHERE t1.NUM_ID <= 0;
Ecco il piano:
È un piano davvero negativo. Invece di utilizzare l'indice, Oracle materializza 10000 X 10000 = 100000000 righe in una tabella temporanea solo per restituire infine 0 righe. Il costo di questo piano è di circa 6 M, che è molto più alto rispetto all'altra query. Il completamento della query ha richiesto 68 secondi sul mio computer.
Si noti che la query potrebbe non essere riuscita se non vi è memoria o spazio libero sufficienti nel tablespace temporaneo.
Posso usare il INLINE
suggerimento non documentato per impedire all'ottimizzatore di materializzare il CTE:
WITH N_10000_CTE AS (
SELECT /*+ INLINE */ n1.NUM_ID
FROM N_10000 n1
CROSS JOIN N_10000 n2
)
SELECT t1.NUM_ID
FROM N_10000_CTE t1
LEFT JOIN N_10000_CTE t2 ON t1.NUM_ID = t2.NUM_ID
WHERE t1.NUM_ID <= 0;
Quella query è in grado di utilizzare l'indice e termina quasi all'istante. Il costo della query è lo stesso di prima, 11. Quindi, per la seconda query, l'euristica utilizzata da Oracle l'ha ottenuta selezionando una query con un costo stimato di 6 M anziché una query con un costo stimato di 11.
WITH...
). È possibile riscrivere ogni tabella derivata come CTE, ma forse non viceversa (ad esempio CTE ricorsivo o utilizzando il CTE più volte)