Outras respostas cobrem muito bem as diferenças de sintaxe, portanto não vou entrar nisso. Em vez disso, essa resposta cobrirá apenas o desempenho no Oracle.
O otimizador Oracle pode optar por materializar os resultados de um CTE em uma tabela temporária interna. Ele usa uma heurística para fazer isso, em vez de otimização baseada em custos. A heurística é algo como "Materialize o CTE se não for uma expressão trivial e o CTE for referenciado mais de uma vez na consulta". Existem algumas consultas para as quais a materialização melhorará o desempenho. Existem algumas consultas para as quais a materialização prejudicará drasticamente o desempenho. O exemplo a seguir é um pouco artificial, mas ilustra bem o ponto:
Primeiro, crie uma tabela com uma chave primária que contenha números inteiros de 1 a 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 a seguinte consulta que usa duas tabelas 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 analisar esta consulta e determinar rapidamente que ela não retornará nenhuma linha. A Oracle deve poder usar o índice para determinar isso também. Na minha máquina, a consulta termina quase instantaneamente com o seguinte plano:
Eu não gosto de me repetir, então vamos tentar a mesma consulta com um 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;
Aqui está o plano:
Esse é um plano muito ruim. Em vez de usar o índice, o Oracle materializa 10000 X 10000 = 100000000 linhas em uma tabela temporária apenas para retornar 0 linhas. O custo deste plano é de cerca de 6 M, o que é muito mais alto que a outra consulta. A consulta levou 68 segundos para terminar na minha máquina.
Observe que a consulta pode ter falhado se não houver memória suficiente ou espaço livre no espaço de tabela temporário.
Posso usar a INLINE
dica não documentada para impedir o otimizador de materializar o 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;
Essa consulta é capaz de usar o índice e termina quase instantaneamente. O custo da consulta é o mesmo de antes, 11. Portanto, para a segunda consulta, a heurística usada pelo Oracle resultou na escolha de uma consulta com um custo estimado de 6 M em vez de uma consulta com um custo estimado de 11.
WITH...
). Você pode reescrever cada tabela derivada como uma CTE, mas talvez não o contrário (por exemplo recursiva CTE ou usando os CTE várias vezes)