web-dev-qa-db-fra.com

Différence de performances: condition placée dans la clause INNER JOIN vs WHERE

Disons que j'ai une table order as

id | clientid | type | amount | itemid | date
---|----------|------|--------|--------|-----------
23 | 258      | B    | 150    | 14     | 2012-04-03
24 | 258      | S    | 69     | 14     | 2012-04-03
25 | 301      | S    | 10     | 20     | 2012-04-03
26 | 327      | B    | 54     | 156    | 2012-04-04
  • clientid est une clé étrangère de retour à la table client
  • itemid est une clé étrangère renvoyant à une table item
  • type est seulement B ou S
  • amount est un entier

et une table processed as

id | orderid | processed | date
---|---------|-----------|---------
41 | 23      | true      | 2012-04-03
42 | 24      | true      | 2012-04-03
43 | 25      | false     | <NULL>
44 | 26      | true      | 2012-04-05     

J'ai besoin d'obtenir toutes les lignes de order qui pour le même clientid sur les mêmes date ont des valeurs de type opposées. Gardez à l'esprit que type ne peut avoir qu'une ou deux valeurs - B ou S. Dans l'exemple ci-dessus, ce serait les lignes 23 et 24.

L'autre contrainte est que la ligne correspondante dans processed doit être true pour orderid.

Ma requête jusqu'à présent

SELECT c1.clientid,
       c1.date,
       c1.type,
       c1.itemid,
       c1.amount,
       c2.date,
       c2.type,
       c2.itemid,
       c2.amount

FROM   order c1
INNER JOIN order c2 ON c1.itemid    =  c2.itemid AND
                       c1.date      =  c2.date   AND
                       c1.clientid  =  c2.clientid AND
                       c1.type     <>  c2.type AND
                       c1.id        <  c2.id

INNER JOIN processed p1 ON p1.orderid   =  c1.id AND
                         p1.processed =  true
INNER JOIN processed p2 ON p2.orderid   =  c2.id AND
                         p2.processed =  true

QUESTION: Garder le processed = true dans le cadre de la clause join ralentit la requête. Si je le déplace vers la clause WHERE, les performances sont bien meilleures. Cela a piqué mon intérêt et J'aimerais savoir pourquoi .

Les clés primaires et les colonnes de clés étrangères respectives sont indexées, contrairement aux colonnes de valeurs (value, processed etc).

Avertissement: J'ai hérité de cette structure de base de données et la différence de performances est d'environ 6 secondes.

29
Insectatorious

La raison pour laquelle vous voyez une différence est due au plan d'exécution que le planificateur met en place, cela est évidemment différent selon la requête (sans doute, il devrait être d'optimiser les 2 requêtes pour qu'elles soient identiques et cela peut être un bug ). Cela signifie que le planificateur pense qu'il doit travailler d'une manière particulière pour arriver au résultat dans chaque déclaration.

Lorsque vous le faites dans JOIN, le planificateur devra probablement sélectionner dans le tableau, filtrer par la partie "True", puis joindre les jeux de résultats. J'imagine que c'est une grande table, et donc beaucoup de données à parcourir, et qu'elle ne peut pas utiliser les index aussi efficacement.

Je soupçonne que si vous le faites dans une clause WHERE, le planificateur choisit un itinéraire plus efficace (c'est-à-dire soit basé sur un index, soit un ensemble de données pré-filtré).

Vous pourriez probablement rendre la jointure aussi rapide (sinon plus rapide) en ajoutant un index sur les deux colonnes (vous ne savez pas si les colonnes incluses et les index à colonnes multiples sont encore pris en charge sur Postgres).

En bref, le planificateur est le problème qu'il choisit 2 itinéraires différents pour arriver aux jeux de résultats, et l'un d'eux n'est pas aussi efficace que l'autre. Il nous est impossible de connaître les raisons sans les informations complètes du tableau et les informations EXPLAIN ANALYZE.

Si vous voulez des détails sur la raison pour laquelle votre requête spécifique fait cela, vous devrez fournir plus d'informations. Cependant, la raison en est que le planificateur choisit différents itinéraires.

Matériel de lecture supplémentaire:

http://www.postgresql.org/docs/current/static/explicit-joins.html

Juste effleuré, il semble que le planificateur postgres ne réorganise pas les jointures pour l'optimiser. essayez de changer l'ordre des jointures dans votre instruction pour voir si vous obtenez alors les mêmes performances ... juste une pensée.

9
Martin