PostgreSQL
 sql >> Datenbank >  >> RDS >> PostgreSQL

Was ist der Unterschied zwischen LATERAL JOIN und einer Unterabfrage in PostgreSQL?

Was ist a LATERAL beitreten?

Die Funktion wurde mit PostgreSQL 9.3 eingeführt. Das Handbuch:

Unterabfragen, die in FROM erscheinen kann das Schlüsselwort LATERAL vorangestellt werden . Dadurch können sie auf Spalten verweisen, die durch vorangestelltes FROM bereitgestellt werden Produkte. (Ohne LATERAL , wird jede Unterabfrage unabhängig ausgewertet und kann daher nicht auf andere FROM verweisen Element.)

Tabellenfunktionen, die in FROM erscheinen kann auch das Schlüsselwort LATERAL vorangestellt werden , aber für Funktionen ist das Schlüsselwort optional; Die Argumente der Funktion können Verweise auf Spalten enthalten, die durch vorangestelltes FROM bereitgestellt werden Artikel auf jeden Fall.

Dort finden Sie grundlegende Codebeispiele.

Eher wie eine korrelierte Unterabfrage

A LATERAL join ist eher wie eine korrelierte Unterabfrage, nicht eine einfache Unterabfrage, da die Ausdrücke rechts von einem LATERAL stehen Join werden einmal für jede Zeile links davon ausgewertet - genau wie ein correlated Unterabfrage - während eine einfache Unterabfrage (Tabellenausdruck) einmal ausgewertet wird nur. (Der Abfrageplaner hat jedoch Möglichkeiten, die Leistung für beide zu optimieren.)
Verwandte Antwort mit Codebeispielen für beide nebeneinander, die dasselbe Problem lösen:

  • Optimieren Sie die GROUP BY-Abfrage, um die neueste Zeile pro Benutzer abzurufen

Zur Rückgabe von mehr als einer Spalte , ein LATERAL Join ist normalerweise einfacher, sauberer und schneller.
Denken Sie auch daran, dass das Äquivalent einer korrelierten Unterabfrage LEFT JOIN LATERAL ... ON true ist :

  • Rufen Sie eine Set-zurückgebende Funktion mehrmals mit einem Array-Argument auf

Dinge, die eine Unterabfrage nicht kann

Es gibt Dinge, die ein LATERAL join kann dies tun, aber eine (korrelierte) Unterabfrage kann dies (ohne weiteres) nicht. Eine korrelierte Unterabfrage kann nur einen einzelnen Wert zurückgeben, nicht mehrere Spalten und nicht mehrere Zeilen – mit Ausnahme von bloßen Funktionsaufrufen (die Ergebniszeilen multiplizieren, wenn sie mehrere Zeilen zurückgeben). Aber auch bestimmte satzrückgebende Funktionen sind nur im FROM erlaubt Klausel. Wie unnest() mit mehreren Parametern in Postgres 9.4 oder höher. Das Handbuch:

Dies ist nur im FROM erlaubt Klausel;

Das funktioniert also, kann aber nicht (leicht) durch eine Unterabfrage ersetzt werden:

CREATE TABLE tbl (a1 int[], a2 int[]);
SELECT * FROM tbl, unnest(a1, a2) u(elem1, elem2);  -- implicit LATERAL

Das Komma (, ) im FROM -Klausel ist eine Kurzschreibweise für CROSS JOIN .
LATERAL wird automatisch für Tabellenfunktionen angenommen.
Über den Spezialfall von UNNEST( array_expression [, ... ] ) :

  • Wie deklarieren Sie eine Set-Returning-Funktion so, dass sie nur in der FROM-Klausel erlaubt ist?

Set-zurückgebende Funktionen im SELECT Liste

Sie können auch Set-Returning-Funktionen wie unnest() verwenden im SELECT direkt auflisten. Dies zeigte früher ein überraschendes Verhalten mit mehr als einer solchen Funktion im selben SELECT Liste bis Postgres 9.6. Aber es wurde endlich mit Postgres 10 bereinigt und ist jetzt eine gültige Alternative (auch wenn es kein Standard-SQL ist). Siehe:

  • Was ist das erwartete Verhalten für mehrere Set-zurückgebende Funktionen in der SELECT-Klausel?

Aufbauend auf obigem Beispiel:

SELECT *, unnest(a1) AS elem1, unnest(a2) AS elem2
FROM   tbl;

Vergleich:

dbfiddle für pg 9.6 hier
dbfiddle für Seite 10 hier

Klarstellen von Fehlinformationen

Das Handbuch:

Für INNER und OUTER Join-Typen muss eine Join-Bedingung angegeben werden, nämlich genau eine von NATURAL , ON join_condition , oder USING (join_column [, ...]). Siehe unten für die Bedeutung.
Für CROSS JOIN , darf keiner dieser Klauseln vorkommen.

Diese beiden Abfragen sind also gültig (auch wenn sie nicht besonders nützlich sind):

SELECT *
FROM   tbl t
LEFT   JOIN LATERAL (SELECT * FROM b WHERE b.t_id = t.t_id) t ON TRUE;

SELECT *
FROM   tbl t, LATERAL (SELECT * FROM b WHERE b.t_id = t.t_id) t;

Während dies nicht der Fall ist:

SELECT *
FROM   tbl t
LEFT   JOIN LATERAL (SELECT * FROM b WHERE b.t_id = t.t_id) t;

Deshalb ist das Codebeispiel von Andomar korrekt (der CROSS JOIN erfordert keine Join-Bedingung) und Attilas ist war nicht.