PostgreSQL
 sql >> Base de données >  >> RDS >> PostgreSQL

PostgreSQL :l'utilisation de l'instruction AND dans LEFT JOIN ne fonctionne pas comme prévu

La confusion autour de LEFT JOIN et WHERE clause a été clarifiée à plusieurs reprises :

Cette question intéressante reste :

Il n'y a pas d'indications de requête explicites dans Postgres. (Ce qui fait l'objet d'un débat en cours.) Mais il existe encore diverses astuces pour faire plier Postgres.

Mais d'abord, demandez-vous : Pourquoi le planificateur de requêtes a-t-il estimé que le plan choisi était moins cher au départ ? La configuration de votre serveur est-elle fondamentalement saine ? Paramètres de coût adéquats ? autovacuum fonctionnement? La version de Postgres est obsolète ? Travaillez-vous autour d'un problème sous-jacent qui devrait vraiment être résolu ?

Si vous forcez Postgres à le faire à votre façon, vous devez être sûr qu'il ne se retournera pas, après une mise à niveau de version ou une mise à jour de la configuration du serveur... Vous feriez mieux de savoir exactement ce que vous faites.

Cela dit, vous pouvez forcer Postgres à "filtrer certains enregistrements avant de faire le JOIN " avec une sous-requête où vous ajoutez OFFSET 0 - ce qui n'est que du bruit, logiquement, mais empêche Postgres de le réorganiser sous la forme d'une jointure régulière. (Indice de requête après tout)

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;

Ou vous pouvez utiliser un CTE (moins obscur, mais plus cher). Ou d'autres astuces comme la définition de certains paramètres de configuration. Ou, dans ce cas particulier, j'utiliserais un LATERAL joindre dans le même sens :

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;

Connexe :

Voici un blog détaillé sur les conseils de requête par 2ndQuadrant. Cinq ans mais toujours valide.