2016-11-24 2 views
-1

Diese Abfrage alle Elemente in der Tabelle kommen la und alle Nullen für Felder kehrt aus dem lar Tabelle, die nicht das, was ich erwartet hatte .PostgreSQL: Verwenden von AND-Anweisung in LEFT JOIN wird nicht wie erwartet funktioniert

SELECT 
    la.listing_id, 
    la.id, 
    lar.* 
FROM la 
LEFT JOIN lar 
ON lar.application_id = la.id AND la.listing_id = 2780; 

enter image description here

Diese Abfrage gibt korrekte und erwartete Ergebnisse sollten aber nicht beide Abfragen das gleiche tun? hier

SELECT 
    la.listing_id, 
    la.id, 
    lar.* 
FROM la 
LEFT JOIN lar 
ON lar.application_id = la.id 
WHERE la.listing_id = 2780; 

enter image description here

Was bin ich?

Ich möchte bedingte Joins machen, da ich festgestellt habe, dass Postgresql für komplexe Abfragen die Join dann die WHERE-Klausel tun, die eigentlich sehr langsam ist. Wie macht man die Datenbank vor dem JOIN einige Datensätze ausfiltern?

+1

Sie fragen zwei verschiedene Dinge. Die Abfragen sind unterschiedlich und werden nicht dasselbe tun. In Bezug auf die Geschwindigkeit brauchen Sie wahrscheinlich Index. Versuchen Sie 'EXPLAIN ANALYSE ' –

+0

Warum sind sie anders? –

+0

Können Sie uns beide Ergebnisse zeigen? –

Antwort

0

Das Schlüsselwort LEFT kehrt alle Zeilen von der linken Tabelle (Tabelle 1) JOIN, mit den passenden Zeilen in der rechten Tabelle (Tabelle 2). Das Ergebnis ist NULL auf der rechten Seite, wenn keine Übereinstimmung vorhanden ist.

Also egal, dass Sie versuchen, mit AND la.listing_id = 2780; zu filtern, erhalten Sie immer noch alle Zeilen aus der ersten Tabelle. Aber nur diejenigen mit la.listing_id = 2780; wird etwas <> NULL auf der rechten Seite haben

Das Verhalten unterscheidet, wenn Sie INNER JOIN versuchen in diesem Fall nur die passenden Spalten erstellt werden und die AND Zustand werden die Zeilen filtern.

So ist die erste Abfrage Arbeit, die Sie WHERE la.listing_id IS NOT NULL

Das Problem mit dem zweiten Abfrage hinzufügen müssen machen ist, wird jede Zeile zu JOIN versuchen und filtert dann nur die, die Sie benötigen.

1

Die Verwirrung um LEFT JOIN und WHERE Klausel wurde viele Male geklärt:

Diese interessante Frage bleibt:

Wie die Datenbank machen einige herausfiltern Aufzeichnungen vor dem JOIN?

In Postgres gibt es keine expliziten Abfragehinweise. (Was derzeit diskutiert wird.) Aber es gibt immer noch verschiedene Tricks, um Postgres den Weg zu bahnen.

Aber zuerst, fragen Sie sich: Warum schätzte der Abfrageplaner den gewählten Plan, um am Anfang billiger zu sein?Ist Ihre Serverkonfiguration grundsätzlich vernünftig? Kosteneinstellungen angemessen? autovacuum läuft? Postgres-Version veraltet? Arbeiten Sie an einem zugrunde liegenden Problem, das eigentlich behoben werden sollte?

Wenn Sie Postgres zwingen, es auf Ihre Art zu tun, sollten Sie sicher sein, dass es nicht zurückfeuert, nach einem Versionsupgrade oder einem Update auf die Serverkonfiguration ... Sie sollten besser wissen, was Sie gerade tun.

Das heißt, Sie können Kraft Postgres „einige Datensätze herauszufiltern, bevor der JOIN tun“ mit einer Unterabfrage, wo OFFSET 0 Sie hinzufügen - das ist nur Lärm, logisch, aber verhindert, dass Postgres es in die Form neu anordnen eines regulären Joins. (Abfrage Hinweis immerhin)

SELECT la.listing_id, la.id, lar.* 
FROM (
    SELECT listing_id, id 
    FROM la 
    WHERE listing_id = 2780 
    OFFSET 0 
    ) la 
LEFT JOIN lar ON lar.application_id = la.id; 

Oder Sie können ein CTE (weniger obskur, aber teurer) verwenden. Oder andere Tricks wie das Setzen bestimmter Config-Parameter. Oder in diesem speziellen Fall würde ich ein LATERAL auf den gleichen Effekt kommen:

SELECT la.listing_id, la.id, lar.* 
FROM la 
LEFT JOIN LATERAL (
    SELECT * 
    FROM lar 
    WHERE application_id = la.id 
    ) lar ON true 
WHERE la.listing_id = 2780; 

Verwandte:

Here is an extensive blog on Query hints by 2ndQuadrant. Fünf Jahre alt, aber immer noch gültig.

Verwandte Themen