L'utilisation de SUM () est-elle deux fois moins optimale?

8

Je sais que je dois écrire SUMdeux fois, si je souhaite l'utiliser dans une HAVINGclause (ou utiliser une table dérivée sinon):

SELECT  id,
  sum(hours) AS totalhours
  FROM mytable
  GROUP BY id
  HAVING sum(hours) > 50;

Ma question est maintenant de savoir si ce n'est pas optimal ou non. En tant que programmeur, cette requête ressemble à la base de données va calculer la somme deux fois. Est-ce le cas, ou devrais-je compter sur des optimisations que le moteur DB fera pour moi?

Mise à jour: explication d'une requête comparable:

postgres=> explain select sum(counttodo) from orderline group by orderlineid having sum(counttodo) > 100;
                             QUERY PLAN                             
--------------------------------------------------------------------
 HashAggregate  (cost=1.31..1.54 rows=18 width=8)
   Filter: (sum(counttodo) > 100)
   ->  Seq Scan on orderline  (cost=0.00..1.18 rows=18 width=8)
(3 rows)
Bart Friederichs
la source
pouvez-vous poster l'expliquer?
Ste
Je ne répondrai pas à cela car il y a une explication agréable et concise ici : "Au cas où vous vous demandez pourquoi vous ne pouvez pas faire référence aux alias SELECT plus tard dans la requête, comme dans la clause WHERE, tout est à voir avec l'ordre d'évaluation. SQL n'est pas évalué dans l'ordre dans lequel il est écrit. La liste SELECT est en fait évaluée presque en dernier et son contenu n'existe pas encore lorsque HAVING etc. est traité. Cela devient important lorsque la liste de sélection comprend des fonctions avec effets secondaires [...] "
dezso
... c'est pourquoi vous ne pouvez pas simplement référencer la colonne agrégée dans la HAVINGclause - mais, à ma connaissance, en interne, cela se fait plutôt dans l'autre sens.
dezso
2
@BartFriederichs bien, beaucoup de gens se plaignent à côté de ces lignes (je m'étais plaint aussi jusqu'à ce que je ne m'y habitue pas ...) Il n'est pas exécuté deux fois et pourrait probablement être fait en utilisant un alias dans HAVING(puis en tirant la définition de la colonne de la SELECTclause) - pour une raison quelconque, ils ne le font tout simplement pas.
dezso
3
Je pense que laisser le moteur DB s'inquiéter des optimisations devrait être une seconde nature pour un praticien SGBDR. SQL est un 4GL, nous définissons donc le jeu de résultats que nous voulons, pas les moyens par lesquels il est atteint. Il y a beaucoup d'autres problèmes sur lesquels nous ne nous inquiétons pas pour la plupart - l'ordre de jointure, ou la transformation d'EXISTS en jointure par exemple. Ce problème particulier est davantage un problème du point de vue "Ne vous répétez pas" pour les expressions complexes, mais des solutions de contournement judicieuses (vues en ligne, CTE) peuvent vous aider.
David Aldridge

Réponses:

3

La somme n'est calculée qu'une seule fois.

J'ai vérifié cela en utilisant

create table mytable (id int, hours int);
insert into mytable values (1, 60);
select sum(hours) from mytable group by id having sum(hours) > 50;

puis utilisé un débogueur pour vérifier combien de fois int4_sum(la fonction de transition derrière l' sumagrégat) a été appelée: une fois.

Peter Eisentraut
la source
0

Comparez votre requête

explain
select sum(counttodo)
from orderline
group by orderlineid
having sum(counttodo) > 100

À cet équivalent, vérifiez ce qu'ils diffèrent

explain
select *
from (
    select sum(counttodo) counttodo
    from orderline
    group by orderlineid
) s
where counttodo > 100
Clodoaldo
la source
1
Je peux voir où vous en êtes, mais dans sa forme actuelle, cela ne constitue pas une «bonne» réponse. Postez l'explication pour chacun avec un peu plus de commentaires et vous êtes bon pour quelques votes positifs.
Mark Storey-Smith,
0

Vous ne devez écrire SUMdeux fois si vous n'avez pas besoin de le récupérer; si vous êtes seulement intéressé par le fait d' idavoir un, SUM(hours) > 50alors ce qui suit est parfaitement valable:

SELECT id,
FROM mytable
GROUP BY id
HAVING sum(hours) > 50;
Colin 't Hart
la source