Otras respuestas cubren las diferencias de sintaxis bastante bien, así que no voy a entrar en eso. En cambio, esta respuesta solo cubrirá el rendimiento en Oracle.
El optimizador de Oracle puede optar por materializar los resultados de un CTE en una tabla temporal interna. Utiliza una heurística para hacer esto en lugar de la optimización basada en costos. La heurística es algo así como "Materializar el CTE si no es una expresión trivial y se hace referencia al CTE más de una vez en la consulta". Hay algunas consultas para las cuales la materialización mejorará el rendimiento. Hay algunas consultas para las cuales la materialización degradará drásticamente el rendimiento. El siguiente ejemplo es un poco artificial pero ilustra bien el punto:
Primero cree una tabla con una clave primaria que contenga enteros del 1 al 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;
Considere la siguiente consulta que usa dos tablas derivadas:
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;
Podemos ver esta consulta y determinar rápidamente que no devolverá ninguna fila. Oracle debería poder usar el índice para determinar eso también. En mi máquina, la consulta finaliza casi instantáneamente con el siguiente plan:
No me gusta repetirme, así que intentemos la misma consulta 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;
Aquí está el plan:
Ese es un plan realmente malo. En lugar de usar el índice, Oracle materializa 10000 X 10000 = 100000000 filas en una tabla temporal solo para eventualmente devolver 0 filas. El costo de este plan es de alrededor de 6 M, que es mucho más alto que la otra consulta. La consulta tardó 68 segundos en finalizar en mi máquina.
Tenga en cuenta que la consulta podría haber fallado si no hay suficiente memoria o espacio libre en el espacio de tabla temporal.
Puedo usar la INLINE
sugerencia no documentada para evitar que el optimizador materialice el 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;
Esa consulta puede usar el índice y finaliza casi al instante. El costo de la consulta es el mismo que antes, 11. Entonces, para la segunda consulta, la heurística utilizada por Oracle resultó en que eligiera una consulta con un costo estimado de 6 M en lugar de una consulta con un costo estimado de 11.
WITH...
). Puede volver a escribir cada tabla derivada como CTE, pero tal vez no al revés (por ejemplo CTE recursiva o el uso de los CTE varias veces)