Dies ist eine Frage zum Kurzschließen teurer JOINs oder Unterabfragen in Postgresql (9.5 oder 9.6). Ich bin auch daran interessiert zu hören, wie Leute im Allgemeinen das Check-Then-Execute-Problem lösen.
Ich schreibe viele Abfragen, die nur bedingt ein Ergebnis zurückgeben sollten, z. B. ob der (Web-) Benutzer den Datensatz besitzt oder ob der Datensatz geändert wurde. Ich versuche zu verhindern, dass teure Ansichten in Postgresql und mehrere Hin- und Her-Abfragen erstellt werden, um in der Anwendung selbst nach Bedingungen zu suchen. Daher versuche ich, Abfragen zu schreiben, die zuerst den richtigen Datensatz auswählen und anzeigen, welche Bedingungen fehlgeschlagen sind, und nur die auszuführen anzeigen, ob die Bedingungen erfüllt sind.
Dies prüft beispielsweise, ob der (Anwendungs-) Benutzer einen Datensatz besitzt, bevor er zurückgegeben wird:
SELECT is_owner, is_newer, json
FROM (
SELECT id, owner = '053bffbc-c41e-dad4-853b-ea91fc42ea18' "is_owner"
, modified >= created "is_newer"
FROM datasets
WHERE id = '056e4eed-ee63-2add-e981-0c86b8b6a66f'
) cond
LEFT JOIN LATERAL (
SELECT id
FROM datasets
WHERE is_owner and is_newer
) authed
ON cond.id = authed.id
LEFT JOIN LATERAL (
SELECT json
FROM view_dataset
WHERE id = authed.id
) dataset
ON true;
Ergebnis (ist Eigentümer):
is_owner | is_newer | json
t t {...}
Und ein negatives Ergebnis (nicht Eigentümer):
is_owner | is_newer | json
f t NULL
Die Anwendung weiß also, welcher Fehler zurückgegeben werden soll, aber wir müssen die Ansicht nicht erstellen oder analysieren, wenn die Bedingungen nicht erfüllt sind.
EXPLAIN ANALYZE zeigt jedoch, dass Postgresql die Ansichtsabfrage im letzten LEFT LATERAL JOIN weiterhin ausführt, obwohl der mittlere JOIN keine Ergebnisse hat , und ich kann ihn nicht kurzschließen, um zu verhindern, dass das (teure) view_dataset SELECT ausgeführt wird . Wenn ich json
auf null
die Abfrage setze , wird alles außer dem ersten SELECT übersprungen. Wenn es jedoch auf einen Wert aus der letzten Abfrage festgelegt ist, werden immer alle SELECTs ausgeführt. Ich denke, der Abfrageplaner ist der Meinung, dass er ein Ergebnis für dieses json
Feld in der obersten SELECT-Abfrage erhalten muss, und schließt die JOINs nicht kurz .
Ich frage mich, ob ich Postgresql zwingen kann, die teure Ansichtsabfrage zu löschen.
Ich habe auch einen CTE ausprobiert, der die JOIN-Abfrage zu überspringen scheint:
WITH cond as (
SELECT id, owner = '053bffbc-c41e-dad4-853b-ea91fc42ea18' "is_owner", modified >= created "is_newer" FROM datasets WHERE id = '056e4eed-ee63-2add-e981-0c86b8b6a66f'
)
SELECT cond.id, cond.is_owner, cond.is_newer, json FROM
(SELECT id FROM cond WHERE cond.is_owner and cond.is_newer) filtered
LEFT JOIN LATERAL
(SELECT id, json from view_dataset) dataset
USING (id)
RIGHT JOIN cond
USING(id);
... aber diese Abfrage und Variationen sind mindestens 2x langsamer.
Meine Frage ist also, wie die Leistung maximiert werden kann, indem JOINs oder Unterabfragen basierend auf den Bedingungen kurzgeschlossen werden. und ich bin auch interessiert zu hören, ob jemand andere Ideen hat, wie man ein Muster, bei dem zuerst geprüft und dann ausgeführt wird, implementiert, z. B. das Überprüfen des Datensatzbesitzes.
quelle
) dataset ON true;
zu) dataset ON is_owner;
?Antworten:
Nicht sicher, warum überhaupt
authed
benötigt wird. Was macht:von dir? Ich stimme auch dem Kommentar von a_horse_with_no_name zu . LATERAL kann in besonderen Fällen eine enorme Hilfe sein, um Prädikate in die Basistabellen zu verschieben. Es handelt sich jedoch nur um eine getarnte Unterabfrage. In den meisten Fällen ist es daher sinnvoller, einen normalen Join durchzuführen. Versuchen Sie auch:
BEARBEITEN. Tabellenwertfunktion
und verwenden Sie diese Funktion dann in Ihrer Abfrage als:
Alles ungetestet.
quelle
left join view_dataset as dataset on dataset.id = cond.id and cond.is_owner and cond.is_newer