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 entieret 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.
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.