Postgres newbie here.
Je me demande si cette requête est optimisée ou non? J'ai essayé de JOIN ON uniquement les valeurs qui sont 100% nécessaires et en laissant toutes les conditions dynamiques dans la clause WHERE. Voir ci-dessous.
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;
Remarque: Pour le contexte, ce proc vérifie si un utilisateur est également un employé (privilèges élevés/type d'utilisateur différent).
Quoi qu'il en soit, est-ce la bonne façon de procéder? Est-ce que JOIN ON devrait contenir plus d'instructions comme vérifier expired_at IS NULL, par exemple? Pourquoi ou pourquoi cela n'a-t-il pas de sens?
Logiquement , cela ne fait aucune différence que vous placiez des conditions dans la clause join d'un INNER JOIN
ou la clause WHERE
de la même SELECT
. L'effet est le même.
(Pas le cas pour OUTER JOIN
!)
Tout en fonctionnant avec les paramètres par défaut, cela ne fait aucune différence pour le plan de requête ou les performances . Postgres est libre de réorganiser les jointures et les conditions JOIN
& WHERE
dans sa quête du meilleur plan de requête - tant que le nombre de tables n'est pas supérieur à (join_collapse_limit
(par défaut 8
). Détails:
Pour la lisibilité et la maintenabilité , il est logique de placer les conditions qui connectent les tables dans la clause JOIN
respective et les conditions générales dans la WHERE
clause.
Votre requête semble très bien. J'utiliserais des alias de table pour réduire le bruit, cependant.
Détail mineur:
int2 '1'
ou même 1::int2
sont plus sensés que (1)::INT2
. Et en comparant à une valeur de type de données numérique bien défini, une constante numérique simple 1
est assez bien aussi.
Quelques points ..
Si vous vous joignez à une condition du même nom (user_id
) Dans votre cas, vous pouvez utiliser USING (user_id)
plutôt que ON (a.user_id = b.user_id)
. Cela évite également qu'une colonne redondante ne soit potentiellement sortie (si vous exécutez SELECT *
En production).
1::int2
Est problématique. Soit status
, et is_primary
Et d'autres sont déjà int2
, Auquel cas le littéral 1 sera automatiquement casté en int2, ou int2 casté en int comme pg le juge bon. Ou, si vous les stockez en tant qu'ints réguliers et que vous les jetez comme si cela faisait une différence dans le calcul - ce qui n'est pas le cas, le casting seul en fait une proposition perdante.
Lorsque cela est possible, tous les :: int2 devraient probablement être stockés sous boolean
. Ensuite, vous pouvez écrire votre condition WHERE
pour être aussi plus simple.
Pour votre type et votre statut, vous souhaiterez peut-être un type ENUM
.