In der oracle world, wie erklärt here, die WITH abfrage_name-Klausel können Sie einen Namen zu einem Unterabfrage-Block zuweisen. Sie können dann auf den Unterabfrageblock mehrere Stellen in der Abfrage verweisen, indem Sie den Abfragenamen angeben. Oracle optimiert die Abfrage, indem der Abfragename entweder als Inline-Ansicht oder als temporäre Tabelle behandelt wird.
Sie können diese Klausel in jeder SELECT-Anweisung auf oberster Ebene und in den meisten Arten von Unterabfragen angeben. Der Name der Abfrage ist für die Hauptabfrage und für alle nachfolgenden Unterabfragen sichtbar, mit Ausnahme der Unterabfrage, die den Abfragesamen selbst definiert.
Eine WITH-Klausel ist am wertvollsten, wenn das Ergebnis der WITH-Abfrage mehr als einmal im Hauptteil der Hauptabfrage benötigt wird, z. B. wenn ein Durchschnittswert zwei- oder dreimal verglichen werden soll. Der Zweck besteht darin, die Anzahl der Zugriffe auf eine Tabelle zu minimieren, die mehrfach in einer einzelnen Abfrage verknüpft ist.
Einschränkungen bei Subquery Factoring:
Sie können diese Klausel nicht verschachtelt werden. Das heißt, Sie können die subquery_factoring_clause nicht in der Unterabfrage einer anderen subquery_factoring_clause angeben. Ein query_name, der in einer Unterabfrage_factoring_klause definiert ist, kann jedoch in der Unterabfrage jeder nachfolgenden Unterabfrage_factoring_klausel verwendet werden.
In einer Abfrage mit Mengenoperatoren darf die Mengenoperator-Unterabfrage nicht die Unterabfrage_factoring_klause enthalten, aber die FROM-Unterabfrage kann die Unterabfrage_factoring_klause enthalten.
In Ihrem Fall haben Sie eine zufällige Funktion verwendet, die vom Optimierer anders behandelt wird, da er als Inline-Ansicht und nicht als materialisierte Perspektive behandelt wird. Als @ ibre5041 vorgeschlagen, verwenden Sie eine EXPLAIN PLAN
für verschiedene Fälle.
Betrachten Sie den Fall eines rekursiven CTE, es wird intern jedes Mal verwendet.
WITH generator (value) AS (
SELECT 1 FROM DUAL
UNION ALL
SELECT value + 1
FROM generator
WHERE value < 10
)
SELECT value
FROM generator;
Plan hash value: 1492144221
--------------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
--------------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 2 | 26 | 4 (0)| 00:00:01 |
| 1 | VIEW | | 2 | 26 | 4 (0)| 00:00:01 |
| 2 | UNION ALL (RECURSIVE WITH) BREADTH FIRST| | | | | |
| 3 | FAST DUAL | | 1 | | 2 (0)| 00:00:01 |
|* 4 | RECURSIVE WITH PUMP | | | | | |
--------------------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
4 - filter("VALUE"<10)
Postgres gibt die gleiche Anzahl für beide äußeren auswählt. Der CTE wird also nur einmal ausgeführt. –
In Oracle 'WITH test (rnd) AS (SELECT/* + MATERIALISIEREN */DBMS_RANDOM.VALUE FROM DUAL) SELECT 'a', t. * FROM test t UNION ALL SELECT 'b', t. * FROM test t; 'gibt für beide die gleiche Zahl. – MT0