Ist die Verwendung von SUM () zweimal suboptimal?


8

Ich weiß SUM, dass ich zweimal schreiben muss , wenn ich es in einer HAVINGKlausel verwenden möchte (oder eine abgeleitete Tabelle anderweitig verwenden möchte ):

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

Meine Frage ist nun, ob dies nicht optimal ist oder nicht. Als Programmierer sieht diese Abfrage so aus, als würde die DB die Summe zweimal berechnen. Ist das so oder sollte ich mich auf Optimierungen verlassen, die die DB-Engine für mich vornehmen wird?

Update: eine Erklärung einer vergleichbaren Abfrage:

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)

Kannst du die Erklärung posten?
Ste

Ich werde darauf nicht antworten, da es hier eine nette, prägnante Erklärung gibt : "Falls Sie sich fragen, warum Sie später in der Abfrage nicht auf die SELECT-Aliase verweisen können, wie in der WHERE-Klausel, hat dies alles mit der Reihenfolge zu tun SQL wird nicht in der Reihenfolge ausgewertet, in der es geschrieben wurde. Die SELECT-Liste wird tatsächlich fast zuletzt ausgewertet, und ihr Inhalt existiert noch nicht, wenn HAVING usw. verarbeitet werden. Dies wird wichtig, wenn die Auswahlliste Funktionen mit enthält Nebenwirkungen [...] "
dezso

... aus diesem Grund können Sie nicht einfach auf die aggregierte Spalte in der HAVINGKlausel verweisen - nach meinem Verständnis erfolgt dies intern eher umgekehrt.
Dekso

2
@BartFriederichs gut, viele Leute beschweren sich neben diesen Zeilen (ich hatte mich auch beschwert, bis ich mich nicht daran gewöhnt habe ...). Es wird nicht zweimal ausgeführt und könnte wahrscheinlich durch Verwendung eines Alias ​​in HAVING(und anschließendes Ziehen der Spaltendefinition) erfolgen aus der SELECTKlausel) - aus irgendeinem Grund tun sie das einfach nicht.
Dekso

3
Ich denke, dass es für einen RDBMS-Praktiker selbstverständlich sein sollte, die DB-Engine über Optimierungen sorgen zu lassen. SQL ist eine 4GL, daher definieren wir die gewünschte Ergebnismenge und nicht die Mittel, mit denen sie erreicht wird. Es gibt viele andere Probleme, über die wir uns größtenteils keine Sorgen machen - beispielsweise die Join-Reihenfolge oder die Umwandlung von EXISTS in einen Join. Dieses spezielle Problem ist aus der Perspektive "Wiederholen Sie sich nicht" eher ein Problem für komplexe Ausdrücke, aber sinnvolle Problemumgehungen (Inline-Ansichten, CTEs) können dabei helfen.
David Aldridge

Antworten:


3

Die Summe wird nur einmal berechnet.

Ich habe dies mit überprüft

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;

und dann mit einem Debugger überprüft, wie oft int4_sum(die Übergangsfunktion hinter dem sumAggregat) aufgerufen wurde: einmal.


0

Vergleichen Sie Ihre Anfrage

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

Zu diesem Äquivalent wird geprüft, was sie unterscheiden

explain
select *
from (
    select sum(counttodo) counttodo
    from orderline
    group by orderlineid
) s
where counttodo > 100

1
Ich kann sehen, worauf Sie hinaus wollen, aber in der aktuellen Form ist dies keine "gute" Antwort. Veröffentlichen Sie die Erklärung für jeden mit etwas mehr Kommentaren und Sie sind gut für ein paar positive Stimmen.
Mark Storey-Smith

0

Sie müssen nicht haben , schreiben SUMzweimal , wenn Sie es nicht abrufen müssen; Wenn Sie nur daran interessiert sind, dass die ids eine haben, SUM(hours) > 50dann ist Folgendes vollkommen gültig:

SELECT id,
FROM mytable
GROUP BY id
HAVING sum(hours) > 50;
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.