USING construit dans la clause JOIN peut-il introduire des barrières d'optimisation dans certains cas?

35

Il a été porté à mon attention que la USINGconstruction (au lieu de ON) dans la FROMclause de SELECTrequête pourrait introduire des barrières d'optimisation dans certains cas.

Je veux dire ce mot clé:

SELECT *
De
JOIN b USING (a_id)

Juste dans des cas plus complexes.

Contexte: ce commentaire à cette question .

J'utilise beaucoup cela et je n'ai jamais rien remarqué jusqu'à présent. Je serais très intéressé par un cas de test démontrant l'effet ou des liens vers des informations supplémentaires. Mes efforts de recherche ont été vides.

La réponse parfaite serait un test à démontrer USING (a_id)avec des performances inférieures par rapport à la clause de jointure alternative ON a.a_id = b.a_id, si cela peut réellement se produire.

Erwin Brandstetter
la source
2
@kgrittn: C'est ce à quoi je m'attendais généralement jusqu'à présent: c'est un USINGpeu plus rapide , car il en résulte une colonne de moins dans la matrice de résultats. Vos conclusions remontent à 2005 et 2008. Je suppose que tous les problèmes ont été résolus à ce jour. Cependant , je vois une limite possible: il USINGpeut être nécessaire d’ appliquer des joints avec ordre , car la colonne de jointure résultante est un produit joint. De ce fait, limitant potentiellement les options de réorganisation des JOIN.
Erwin Brandstetter
1
J'ai trouvé ce fil qui pouvait m'empêcher de l'utiliser autant de fois que je l'avais fait, car VIEW avec une condition USING sur une jointure peut poser des problèmes de dump / restore: archives.postgresql.org/pgsql- bugs / 2011-06 / msg00030.php J'ai encore le sentiment persistant qu'il y avait un autre fil lié aux problèmes de performance liés à USING, où la solution de contournement était d'utiliser ON, mais je vais renoncer à le trouver, je pense. Il est probablement prudent de l'utiliser en dehors des vues et de ne pas oublier d'essayer ON au lieu d'une étape de diagnostic si une requête est lente.
Kgrittn
1
On dirait que "utiliser" rend le code un peu lisible, mais je suppose que les deux champs ont besoin du même nom. Je ne pense pas que l’utilisation produirait une meilleure performance qu’un "sur", car la base de données a besoin de faire le match de toute façon, c’est comme si un select avait la même performance qu’une jointure (corrigez-moi si je me trompe), La différence est que Join est plus propre et plus facile à entretenir.
Jcho360
2
@HLGEM: C'est juste un nom symbolique, et avec seulement deux tables, comme dans mon exemple, il n'y a pas de place pour la confusion. Pourtant, j'ai modifié la question. Ne voudrait pas encourager l'utilisation malheureuse de idcomme nom de colonne.
Erwin Brandstetter
2
@ChristiaanWesterbeek: Je ne suis pas d'accord. Le "lieu de prédilection" pour la réponse approfondie de Postgres est (toujours) le mailing. Très peu de développeurs Postgres sont actifs sur SO, mais tous les experts et experts Postgres lisent la liste de diffusion
a_horse_with_no_name

Réponses:

12

Erwin: Je suis d’accord avec l’idée que le fait d’utiliser un ordre rigide pourrait bien créer de nombreux cas extrêmes dans lesquels les plans optimaux seraient exclus. J'ai récemment aidé quelqu'un qui avait quelque chose comme ça dans sa requête:

LEFT JOIN ( 
     a 
     JOIN b ON a.id = b.a_id
     JOIN c ON b.c_id = c.id
) ON a.id = something.a_id
LEFT JOIN (
     table1 t1
     JOIN table2 t2 ON t1.some_field = t2.other_field
     JOIN talbe3 t3 ON t2.yafield = t3.something_else
) ON ....
repeat a few more times

Dans son cas, le pire de ces blocs de jointure provoquait une jointure de boucle imbriquée sur environ 200 000 lignes, environ 20 000 fois (calculez le calcul), et puisque les clés ne pouvaient pas être déplacées vers les index, il s'agissait d'un balayage séquentiel. Cela signifiait que la requête globale prenait environ 3 heures à s'exécuter en raison de modifications du plan en cascade. En distribuant la jointure gauche, les clés peuvent être enfoncées et la requête exécutée en quelques secondes. Bien sûr, cela n’est pas exactement équivalent, c’est pourquoi le planificateur ne peut pas les traiter comme équivalents. Il a donc été laissé en place ce plan comme une jointure de hachage, puis une boucle imbriquée, qui était douloureusement lente.

Chaque fois que vous forcez de manière rigide les jointures à passer dans un certain ordre, vous introduisez des cas dans lesquels les informations de filtre de clé peuvent ne pas être encore disponibles lors de l'exécution du plan, et que vous pouvez donc faire ultérieurement dans une jointure d'index rapide / jointure de hachage. Il se peut que vous deviez effectuer beaucoup plus lentement une analyse imbriquée de boucle / séquentielle. Ainsi, bien que le fragment ci-dessus ne soit pas immédiatement équivalent, il présente le même problème.

Chris Travers
la source