somme () et compte ()
Envisager un système de vote mis en œuvre dans PostgreSQL, où chaque utilisateur peut voter en haut ou en bas sur un "foo". Il y a un foo
table qui stocke toutes les "foo de l'information", et un votes
de la table qui stocke les user_id
foo_id
et vote
où vote
est +1 ou -1.
Pour obtenir le vote de pointage pour chaque foo, la requête suivante devrait fonctionner:
SELECT sum(vote) FROM votes WHERE foo.foo_id = votes.foo_id;
Mais, le suivant ne fonctionne tout aussi bien:
(SELECT count(vote) FROM votes
WHERE foo.foo_id = votes.foo_id
AND votes.vote = 1)
- (SELECT count(vote) FROM votes
WHERE foo.foo_id = votes.foo_id
AND votes.vote = (-1))
J'ai actuellement un index sur votes.foo_id
.
Qui est une approche plus efficace? (En d'autres termes, ce qui permettrait de courir plus vite?)
Je suis intéressé par les deux PostgreSQL-réponse spécifique et le général SQL réponse.
MODIFIER
Beaucoup de réponses ont été en tenant compte le cas où vote
est null. J'ai oublié de mentionner qu'il existe un NOT NULL
contrainte sur le vote de la colonne.
Aussi, beaucoup ont souligné que le premier est beaucoup plus facile à lire. Oui, il est certainement vrai, et si un collègue a écrit le 2ème, je serais explose de rage, sauf si il y avait une performance nécessité. Jamais le moins, la question est toujours sur les performances des deux. (Techniquement, si la première requête a été façon plus lent, il ne serait pas un crime pour écrire la deuxième requête.)
source d'informationauteur ryanrhee
Vous devez vous connecter pour publier un commentaire.
Bien sûr, le premier exemple est plus rapide, plus simple et plus facile à lire. Devrait être évident avant même que l'on obtient giflé avec des créatures aquatiques. Alors que
sum()
est légèrement plus cher quecount()
ce qui importe beaucoup, beaucoup plus, c'est que le deuxième exemple besoin de deux analyses.Mais il y a un réelle différencetrop:
sum()
pouvez retournerNULL
oùcount()
ne l'est pas. Je cite le manuel sur l'ensemble des fonctions:Puisque vous semblez avoir un point faible pour l'optimisation des performances, voici un détail que vous aimeriez:
count(*)
est légèrement plus rapide quecount(vote)
. Seulement l'équivalent si le vote estNOT NULL
. Le Test de performance avecexplain analyze
.Sur une inspection plus minutieuse
Les deux requêtes sont syntaxiques non-sens, de façon autonome. Il n'a de sens que si vous les avez copiés à partir de la
SELECT
liste d'un plus grand requête comme:Le point important ici est la sous-requête en corrélation - ce qui peut être bien si vous vous contentez de lire un petite fraction de
votes
dans votre requête. Nous voudrions voir d'autresWHERE
conditions, et vous devriez avoir de correspondance des indices.Dans Postgresql 9.3 ou plus tard, l'alternative, propre, 100 % équivalent solution serait avec
LEFT JOIN LATERAL ... ON true
:Généralement des performances similaires. Détails:
Cependantlors de la lecture de de grandes parties ou de tous les de table
votes
ce sera (beaucoup) plus rapide:Valeurs agrégées dans une sous-requête en premier, ensuite les rejoindre pour la suite.
Sur
USING
:La première sera plus rapide. Vous pouvez l'essayer sur une manière simple.
Produire des données:
Vérifier à la fois
Mais la vérité est qu'ils ne sont pas équivalents, assurez-vous que le premier travail en tant que deuxième, vous devez le traiter pour le
null
cas:Une chose de plus. Si vous utilisez PostgreSQL 9.2, vous pouvez créer votre index avec les deux colonnes, et de cette façon vous pouvez avoir une chance de l'aide de l'index-only scan:
MAIS! Dans certaines situations, cet indice peut être pire, donc vous devriez essayer avec les deux et exécuter
EXPLAIN ANALYZE
pour voir qui est le meilleur, ou même de créer à la fois et de voir laquelle PostgreSQL utilise le plus (et d'exclure les autres).J'attendrais la première requête pour travailler plus vite, car c'est une seule requête et c'est plus lisible (pratique dans le cas où vous auriez à y revenir après un certain temps).
Deuxième requête se compose de deux requêtes. Vous obtenez seulement un résultat comme si c'était une seule requête.
Cela dit, pour être absolument certain de ces fonctionne le mieux pour vous, je voudrais remplir les deux tableaux avec beaucoup de données factices et de vérifier l'exécution de la requête du temps.