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?
SELECT version();
)Antworten:
Logischerweise spielt es überhaupt keine Rolle , ob Sie Bedingungen in die Join-Klausel einer
INNER JOIN
oder in dieWHERE
Klausel derselben einfügenSELECT
. 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
&WHERE
Bedingungen auf der Suche nach dem besten Abfrageplan neu anordnen - solange die Anzahl der Tabellen nicht größer als diejoin_collapse_limit
(Standard8
) ist. Einzelheiten:Aus Gründen der Lesbarkeit und Wartbarkeit ist es sinnvoll, Bedingungen, die Tabellen verbinden, in die jeweilige
JOIN
Klausel und allgemeine Bedingungen in dieWHERE
Klausel aufzunehmen.Ihre Anfrage sieht gut aus. Ich würde jedoch Tabellen-Aliase verwenden, um das Rauschen zu reduzieren.
Kleinigkeit:
int2 '1'
oder sind sogar1::int2
vernünftiger als(1)::INT2
. Und im Vergleich zu einem Wert eines genau definierten numerischen Datentyps ist auch eine einfache numerische Konstante1
gut genug.quelle
Ein paar Punkte ..
Wenn Sie
user_id
in Ihrem Fall unter einer Bedingung mit demselben Namen ( ) beitreten , können SieUSING (user_id)
anstelle von verwendenON (a.user_id = b.user_id)
. Dies verhindert auch, dass eine redundante Spalte möglicherweise ausgegeben wird (wenn SieSELECT *
in der Produktion ausgeführt werden).1::int2
ist problematisch. Entwederstatus
, undis_primary
und andere sind bereitsint2
in 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.Wenn möglich, sollten alle :: int2 wahrscheinlich als gespeichert werden
boolean
. Dann können Sie IhreWHERE
Bedingung schreiben , um auch einfacher zu sein.Für Ihren Typ und Status möchten Sie möglicherweise einen
ENUM
Typ.quelle