Postgres JOIN-Bedingungen vs WHERE-Bedingungen

10

Postgres Neuling hier.

Ich frage mich, ob diese Abfrage optimiert ist oder nicht. Ich habe versucht, nur die Werte zu verbinden, die zu 100% erforderlich sind, und alle dynamischen Bedingungen in der WHERE-Klausel zu belassen. Siehe unten.

SELECT *
    FROM
      myapp_employees
    JOIN myapp_users ON
      myapp_users.user_id=myapp_employees.user_id
    JOIN myapp_contacts_assoc ON
      myapp_contacts_assoc.user_id=myapp_users.user_id
    JOIN myapp_contacts ON
      myapp_contacts.contact_id=myapp_contacts_assoc.contact_id
    WHERE
      myapp_contacts.value='[email protected]' AND
      myapp_contacts.type=(1)::INT2 AND
      myapp_contacts.is_primary=(1)::INT2 AND
      myapp_contacts.expired_at IS NULL AND
      myapp_employees.status=(1)::INT2 AND
      myapp_users.status=(1)::INT2
    LIMIT 1;

Hinweis: Für den Kontext prüft dieser Prozess, ob ein Benutzer auch ein Mitarbeiter ist (erhöhte Berechtigungen / anderer Benutzertyp).

Wie auch immer, ist das der richtige Weg? Sollte JOIN ON weitere Anweisungen enthalten, z. B. die Überprüfung auf expired_at IS NULL? Warum oder warum macht das keinen Sinn?

Dan
quelle
Was ist mit deiner Version von Postgres? ( SELECT version();)
Erwin Brandstetter
@ErwinBrandstetter Ich verwende PostgreSQL 9.3.14. Sollte dies etwas sein, das ich in jeder Funktion benötige?
Dan
2
Nein, wir hier auf dba.SE verlangen von Ihnen, dass Sie relevante Softwareversionen deklarieren, da diese für viele Fragen einen Unterschied machen.
Erwin Brandstetter

Antworten:

13

Logischerweise spielt es überhaupt keine Rolle , ob Sie Bedingungen in die Join-Klausel einer INNER JOINoder in die WHEREKlausel derselben einfügen SELECT. Der Effekt ist der gleiche.

(Nicht der Fall für OUTER JOIN!)

Während des Betriebs mit Standardeinstellungen spielt dies auch keine Rolle für den Abfrageplan oder die Leistung . Postgres kann Joins und JOIN& WHEREBedingungen auf der Suche nach dem besten Abfrageplan neu anordnen - solange die Anzahl der Tabellen nicht größer als die join_collapse_limit(Standard 8) ist. Einzelheiten:

Aus Gründen der Lesbarkeit und Wartbarkeit ist es sinnvoll, Bedingungen, die Tabellen verbinden, in die jeweilige JOINKlausel und allgemeine Bedingungen in die WHEREKlausel aufzunehmen.

Ihre Anfrage sieht gut aus. Ich würde jedoch Tabellen-Aliase verwenden, um das Rauschen zu reduzieren.

Kleinigkeit:

int2 '1'oder sind sogar 1::int2vernünftiger als (1)::INT2. Und im Vergleich zu einem Wert eines genau definierten numerischen Datentyps ist auch eine einfache numerische Konstante 1gut genug.

Erwin Brandstetter
quelle
2

Ein paar Punkte ..

  1. Wenn Sie user_idin Ihrem Fall unter einer Bedingung mit demselben Namen ( ) beitreten , können Sie USING (user_id)anstelle von verwenden ON (a.user_id = b.user_id). Dies verhindert auch, dass eine redundante Spalte möglicherweise ausgegeben wird (wenn Sie SELECT *in der Produktion ausgeführt werden).

  2. 1::int2ist problematisch. Entweder status, und is_primaryund andere sind bereits int2in diesem Fall der wörtlichen 1 automatisch zu int2 gegossen werden werden, oder INT2 zu int gecastet als pg für richtig hält. Oder wenn Sie sie als reguläre Ints speichern und sie so ablegen, als ob dies einen Unterschied in der Berechnung bewirken würde - was nicht der Fall ist, macht die Besetzung allein dies zu einem Verlust.

  3. Wenn möglich, sollten alle :: int2 wahrscheinlich als gespeichert werden boolean. Dann können Sie Ihre WHEREBedingung schreiben , um auch einfacher zu sein.

  4. Für Ihren Typ und Status möchten Sie möglicherweise einen ENUMTyp.

Evan Carroll
quelle