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

Pourquoi la requête la plus naturelle (c'est-à-dire en utilisant INNER JOIN (au lieu de LEFT JOIN)) est très lente

(comme indiqué, je mets une partie de mon commentaire dans une réponse car cela a résolu le problème)

Convertissez les expressions EXISTS en expressions IN.

Cela fonctionne mieux dans ce cas car la requête sera désormais évaluée de manière efficace de "l'intérieur vers l'extérieur" en commençant par la requête qui contient votre facteur le plus limitant :la recherche de texte intégral. Cette requête va retourner un petit ensemble de lignes qui peuvent être recherchées directement par rapport à la clé primaire de la requête externe (WHERE x in (SELECT X...)) au lieu d'appeler la requête "interne" une fois par valeur de la requête externe (ou pour toutes les valeurs dans votre cas d'origine, si je le lis correctement). La méthode EXISTS donne ici des boucles imbriquées (une évaluation d'une requête pour chaque valeur dans une autre) par rapport à la méthode IN utilisant Hash Joins (une méthode d'exécution beaucoup plus efficace dans de nombreux cas, sinon la plupart.

Notez qu'avec la méthode EXISTS, il existe quatre boucles imbriquées qui s'exécutent chacune au moins 3 000 fois. Ce coût s'additionne. Bien qu'il ne s'agisse pas d'une comparaison directe, vous pouvez traiter les boucles imbriquées comme vous le feriez pour les boucles FOR dans le code d'application :chaque fois que vous invoquez une boucle interne, votre estimation de big-O augmente d'un ordre de grandeur :O(n) à O(n^ 2) à O(n^3), etc.

Hash Join ressemble plus à une carte, où deux tableaux sont parcourus en même temps et une opération est effectuée sur les deux. Ceci est à peu près linéaire (O(n)). Pensez à ceux-ci étant imbriqués comme additifs, donc ils iraient de O(n) à O(2n) à O(3n), etc.

Ouais, ouais, je sais que ce n'est pas tout à fait la même chose, mais le fait est que le fait d'avoir plusieurs boucles imbriquées indique généralement un plan de requête lent et la comparaison des deux styles big-O facilite la reconnaissance, je crois.

Les boucles imbriquées et EXISTS ne sont pas mauvaises en soi, mais dans la plupart des cas où il existe une condition de filtre de base qui affecte finalement tout (par exemple, la recherche de texte intégral dans la question), une expression IN (ou, dans certains cas, un bon JOIN) donne un plan beaucoup plus efficace.