Andere Antworten decken die Syntaxunterschiede ziemlich gut ab, daher werde ich nicht darauf eingehen. Stattdessen bezieht sich diese Antwort nur auf die Leistung in Oracle.
Das Oracle-Optimierungsprogramm kann die Ergebnisse eines CTE in einer internen temporären Tabelle materialisieren. Hierzu wird eine Heuristik anstelle einer kostenbasierten Optimierung verwendet. Die Heuristik lautet etwa "Materialisieren Sie den CTE, wenn es sich nicht um einen trivialen Ausdruck handelt und der CTE in der Abfrage mehrmals referenziert wird". Es gibt einige Abfragen, bei denen die Materialisierung die Leistung verbessert. Es gibt einige Abfragen, bei denen die Materialisierung die Leistung dramatisch beeinträchtigt. Das folgende Beispiel ist etwas erfunden, aber es veranschaulicht den Punkt gut:
Erstellen Sie zunächst eine Tabelle mit einem Primärschlüssel, der Ganzzahlen von 1 bis 10000 enthält:
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;
Betrachten Sie die folgende Abfrage, die zwei abgeleitete Tabellen verwendet:
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;
Wir können uns diese Abfrage ansehen und schnell feststellen, dass keine Zeilen zurückgegeben werden. Oracle sollte in der Lage sein, den Index auch dazu zu verwenden. Auf meinem Computer wird die Abfrage fast sofort mit dem folgenden Plan beendet:
Ich wiederhole mich nicht gern, also versuchen wir die gleiche Abfrage mit einem 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;
Hier ist der Plan:
Das ist ein wirklich schlechter Plan. Anstatt den Index zu verwenden, materialisiert Oracle 10000 x 10000 = 100000000 Zeilen in einer temporären Tabelle, um schließlich 0 Zeilen zurückzugeben. Die Kosten für diesen Plan liegen bei 6 Mio., was viel höher ist als bei der anderen Abfrage. Die Abfrage dauerte auf meinem Computer 68 Sekunden.
Beachten Sie, dass die Abfrage möglicherweise fehlgeschlagen ist, wenn im temporären Tabellenbereich nicht genügend Speicher oder freier Speicherplatz vorhanden ist.
Ich kann den undokumentierten INLINE
Hinweis verwenden, um zu verhindern, dass der Optimierer den CTE materialisiert:
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;
Diese Abfrage kann den Index verwenden und wird fast sofort beendet. Die Kosten für die Abfrage sind die gleichen wie zuvor. 11. Für die zweite Abfrage führte die von Oracle verwendete Heuristik dazu, dass eine Abfrage mit geschätzten Kosten von 6 Mio. anstelle einer Abfrage mit geschätzten Kosten von 11 ausgewählt wurde.
WITH...
). Sie können jede abgeleitete Tabelle als CTE umschreiben, aber möglicherweise nicht umgekehrt (z. B. rekursiver CTE oder mehrfache Verwendung des CTE)