Unterschied zwischen Inline-Ansicht und WITH-Klausel?

9

In Inline-Ansichten können Sie aus einer Unterabfrage auswählen, als wäre es eine andere Tabelle:

SELECT
    *
FROM /* Selecting from a query instead of table */
    (
        SELECT
            c1
        FROM
            t1
        WHERE
            c1 > 0
    ) a
WHERE
    a.c1 < 50;

Ich habe gesehen, dass dies mit verschiedenen Begriffen bezeichnet wurde: Inline-Ansichten, WITH-Klausel, CTE und abgeleitete Tabellen. Mir scheint, dass es sich um unterschiedliche herstellerspezifische Syntax für dieselbe Sache handelt.

Ist das eine falsche Annahme? Gibt es technische / Leistungsunterschiede zwischen diesen?

Kshitiz Sharma
quelle
5
Die "offiziellen" Namen von Standard SQL sind Abgeleitete Tabellen (die Oracle Inline View nennt ) und Common Table Expression (= WITH...). Sie können jede abgeleitete Tabelle als CTE umschreiben, aber möglicherweise nicht umgekehrt (z. B. rekursiver CTE oder mehrfache Verwendung des CTE)
Uhr

Antworten:

8

Es gibt einige wichtige Unterschiede zwischen Inline-Ansichten (abgeleitete Tabellen) und WITH-Klausel (CTE) in Oracle. Einige von ihnen sind ziemlich universell, dh sie sind auf andere RDBMS anwendbar.

  1. WITH kann verwendet werden, um rekursive Unterabfragen zu erstellen, Inline-Ansicht -not (soweit ich weiß, gilt das gleiche für alle RDBMS, die CTE unterstützen)
  2. Die Unterabfrage in WITHKlausel wird eher zuerst physisch ausgeführt. In vielen Fällen WITHkann der Optimierer durch Auswahl zwischen und Inline-Ansicht unterschiedliche Ausführungspläne auswählen (ich denke, es ist herstellerspezifisch, möglicherweise sogar versionenspezifisch).
  3. Unterabfragen in WITHkönnen als temporäre Tabelle ausgeführt werden (mir ist nicht bekannt, ob ein anderer Anbieter als Oracle diese Funktion unterstützt).
  4. Unterabfragen in WITHkönnen mehrfach, in anderen Unterabfragen und in der Hauptabfrage referenziert werden (wahr für die meisten RDBMS).
a1ex07
quelle
MySQL (mindestens die neuesten MariaDB-Versionen) kann abgeleitete Tabellen materialisieren (und sogar Indizes hinzufügen).
Ypercubeᵀᴹ
3
Ich möchte hinzufügen, dass die Verwendung von CTEs als Nebeneffekt im Allgemeinen auch für Menschen besser lesbar ist.
Joishi Bodio
@ JoishiBodio: Ich persönlich stimme Ihnen zu, aber die Lesbarkeit ist eine ziemlich subjektive Angelegenheit. Ich würde es lieber vermeiden, es zu erwähnen
a1ex07
Darüber hinaus kann ein CTE auf einen zuvor deklarierten CTE verweisen. Eine abgeleitete Tabelle kann nicht auf eine zuvor deklarierte abgeleitete Tabelle auf derselben Ebene verweisen, es LATERALsei denn, sie wird verwendet.
Lennart
8

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:

guter Plan

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:

schlechter 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 INLINEHinweis 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.

Joe Obbish
quelle
1

Gibt für SQL Server WITH CTEdie temporär benannte Ergebnismenge an, ist jedoch nur für die erste erforderlich CTE. dh

WITH CTE AS (SELECT .... FROM), 
CTE2 AS (SELECT .... FROM)

SELECT CTE.Column, CTE2.Column
FROM CTE
INNER JOIN CTE2 on CTE.Column = CTE2.Column

Dies ist jedoch keine Unterabfrage oder korrelierte Unterabfrage. Es gibt Dinge, die Sie mit einem CTE tun können, was Sie mit einer Unterabfrage in SQL Server nicht tun können, z. B. das Aktualisieren der Tabellen, auf die in einem CTE verwiesen wird. Hier ist ein Beispiel für die Aktualisierung einer Tabelle mit einem CTE.

Eine Unterabfrage wäre so etwas wie

SELECT
   C1,
   (SELECT C2 FROM SomeTable) as C2
FROM Table

Oder eine korrelierte Unterabfrage ist das, was Sie in Ihrem OP angegeben haben, wenn Sie Ihre Ergebnisse basierend auf a.c1 referenzieren / verbinden / einschränken möchten.

Sie sind also definitiv nicht dasselbe, obwohl Sie in vielen Fällen eine oder mehrere dieser Methoden verwenden können, um das gleiche Ergebnis zu erzielen. Es kommt nur darauf an, was das Endergebnis ist.

scsimon
quelle
1

Der Hauptunterschied zwischen withKlausel und einer Unterabfrage in Oracle besteht darin, dass Sie eine Abfrage innerhalb der Klausel mehrmals referenzieren können. Sie können dann einige Optimierungen damit vornehmen, z materialize. B. mithilfe eines Hinweises eine temporäre Tabelle erstellen. Sie können damit auch rekursive Abfragen durchführen, indem Sie innerhalb einer withKlausel auf sich selbst verweisen . Mit einer Inline-Ansicht ist das nicht möglich.

Weitere Informationen finden Sie hier und hier .

Marko Vodopija
quelle
Im Allgemeinen ist ein Materialisierungshinweis nicht erforderlich. Standardmäßig entscheidet der Oracle-Optimierer, ob es sinnvoll ist, den CTE zu materialisieren oder nicht. Sie können die Optimierung des Optimierers jedoch mit einem Hinweis MATERIALIZEbzw. einem Hinweis überschreiben . INLINEfür das Gegenteil.
Wernfried Domscheit
@WernfriedDomscheit das stimmt. Manchmal entscheidet sich der Optimierer jedoch nicht dafür, den CTE zu materialisieren. In diesem Fall ist die Verwendung eines materializeHinweises eine gültige Option. Ich musste es manchmal angeben, wenn ich sehr komplexe Abfragen optimierte, bei denen ich wusste, dass die Materialisierung des CTE dem Ausführungsplan zugute kommen würde.
Marko Vodopija
0

Sie müssen mit CTEs in SQL Server vorsichtig sein, nicht nur mit Oracle. Es gibt Fälle, in denen Abfragen bei der Verwendung von CTEs im Vergleich zu Unterabfragen, Cross Apply usw. viel schlechter abschneiden.

Wie immer ist es wichtig, jede Abfrage unter verschiedenen Lastbedingungen zu testen, um festzustellen, welche am besten funktioniert.

Ähnlich wie bei @scsimon mit Oracle macht MS SQL Server manchmal nicht das, was Sie in Bezug auf die Indexnutzung erwarten.

Wenn Sie dieselben Daten mehrmals verwenden, können CTEs nützlicher sein. Wenn Sie sie nur einmal verwenden, ist eine Unterabfrage in großen Datenmengen häufig schneller.

zB wählen Sie * aus (meine Unterabfrage) verbinden Sie etwas anderes ...

Justin
quelle