Postgres condizioni JOIN vs WHERE condizioni


12

Postgres principiante qui.

Mi chiedo se questa query sia ottimizzata o no? Ho provato a JOIN ON solo i valori necessari al 100% e lasciando tutte le condizioni dinamiche nella clausola WHERE. Vedi sotto.

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='test@gmail.com' 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;

Nota: per il contesto, questo proc sta verificando se un utente è anche un dipendente (privilegi elevati / tipo di utente diverso).

Comunque, è questa la strada giusta da percorrere? JOIN ON dovrebbe contenere più istruzioni come il controllo di expired_at IS NULL, ad esempio? Perché o perché questo non ha senso?


E la tua versione di Postgres? ( SELECT version();)
Erwin Brandstetter,

@ErwinBrandstetter Sto eseguendo PostgreSQL 9.3.14. Dovrebbe essere qualcosa di cui ho bisogno in ogni funzione?
Dan,

2
No, qui su dba.SE ti chiediamo di dichiarare le versioni pertinenti del software, perché fanno la differenza per molte domande.
Erwin Brandstetter,

Risposte:


14

Logicamente , non fa alcuna differenza se si inseriscono condizioni nella clausola join di una INNER JOINo nella WHEREclausola della stessa SELECT. L'effetto è lo stesso.

(Non è il caso di OUTER JOIN!)

Mentre funziona con le impostazioni predefinite, non fa alcuna differenza per il piano di query o le prestazioni . Postgres è libero di riorganizzare unisce e JOIN& WHEREcondizioni nella sua ricerca per il miglior piano di query - fino a quando il numero di tavoli non è superiore al join_collapse_limit(default 8). Dettagli:

Ai fini della leggibilità e della manutenibilità ha senso inserire condizioni che collegano le tabelle nella rispettiva JOINclausola e condizioni generali nella WHEREclausola.

La tua richiesta sembra a posto. Userei alias da tavolo per ridurre il rumore, però.

Dettagli minori:

int2 '1'o addirittura 1::int2sono più sensibili di (1)::INT2. E mentre si confronta con un valore di tipo di dati numerico ben definito, anche una costante numerica semplice 1è abbastanza buona.


2

Un paio di punti ..

  1. Se ti unisci a una condizione con lo stesso nome ( user_id) nel tuo caso, puoi utilizzare USING (user_id)anziché ON (a.user_id = b.user_id). Ciò consente inoltre di evitare che una colonna ridondante venga potenzialmente emessa (se in esecuzione SELECT *in produzione).

  2. 1::int2è problematico. In entrambi i casi status, e is_primarye altri sono già int2nel qual caso il letterale 1 verrà automaticamente castato su int2 o int2 cast su int come meglio crede. Oppure, se li stai memorizzando come ints regolari e li butti giù come se ciò avesse fatto la differenza nel calcolo - cosa che non fa, il cast da solo fa una proposta perdente.

  3. Quando possibile, tutti i :: int2 dovrebbero probabilmente essere memorizzati come boolean. Quindi puoi scrivere le tue WHEREcondizioni per essere anche più semplice.

  4. Per il tipo e lo stato, potresti desiderare un ENUMtipo.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.