2012-10-13 7 views
5

Gibt es einen Standard für SQL-Implementierung für mehrere Aufrufe derselben Aggregatfunktion in derselben Abfrage?Gibt es einen Standard für die Berechnung von SQL-Aggregatfunktionen?

Betrachten wir zum Beispiel das folgende Beispiel basiert auf einem populären Beispiel Schema:

SELECT Customer,SUM(OrderPrice) FROM Orders 
GROUP BY Customer 
HAVING SUM(OrderPrice)>1000 

Vermutlich dauert es Rechenzeit den Wert von SUM (OrderPrice) zu berechnen. Fallen diese Kosten für jede Referenz auf die Aggregatfunktion an oder wird das Ergebnis für eine bestimmte Abfrage gespeichert?

Oder gibt es keinen Standard für die Implementierung von SQL-Engine für diesen Fall?

Antwort

3

Obwohl ich mit vielen verschiedenen DBMS gearbeitet habe, werde ich Ihnen nur das Ergebnis der Beweisführung auf SQL Server zeigen. Betrachten Sie diese Abfrage, die sogar einen CAST im Ausdruck enthält. Beim Betrachten des Abfrageplans wird der Ausdruck sum(cast(number as bigint)) nur einmal verwendet, was als DEFINE:([Expr1005]=SUM([Expr1006])) definiert ist.

set showplan_text on 
select type, sum(cast(number as bigint)) 
from master..spt_values 
group by type 
having sum(cast(number as bigint)) > 100000 

------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- 
    |--Filter(WHERE:([Expr1005]>(100000))) 
     |--Hash Match(Aggregate, HASH:([Expr1004]), RESIDUAL:([Expr1004] = [Expr1004]) DEFINE:([Expr1005]=SUM([Expr1006]))) 
      |--Compute Scalar(DEFINE:([Expr1004]=CONVERT(nchar(3),[mssqlsystemresource].[sys].[spt_values].[type],0), [Expr1006]=CONVERT(bigint,[mssqlsystemresource].[sys].[spt_values].[number],0))) 
       |--Index Scan(OBJECT:([mssqlsystemresource].[sys].[spt_values].[ix2_spt_values_nu_nc])) 

Es kann nicht sehr offensichtlich oben sein, da es nicht das SELECT-Ergebnis nicht zeigt, so habe ich ein *10 auf die Abfrage unten hinzugefügt. Beachten Sie, dass jetzt ein zusätzlicher Schritt DEFINE:([Expr1006]=[Expr1005]*(10)) (Schritte von unten nach oben) enthalten ist, der zeigt, dass der neue Ausdruck eine zusätzliche Berechnung erfordert. Aber auch dies ist optimiert, da es nicht den gesamten Ausdruck neu berechnet - lediglich Expr1005 wird genommen und mit 10 multipliziert!

set showplan_text on 
select type, sum(cast(number as bigint))*10 
from master..spt_values 
group by type 
having sum(cast(number as bigint)) > 100000 

------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ 
    |--Compute Scalar(DEFINE:([Expr1006]=[Expr1005]*(10))) 
     |--Filter(WHERE:([Expr1005]>(100000))) 
      |--Hash Match(Aggregate, HASH:([Expr1004]), RESIDUAL:([Expr1004] = [Expr1004]) DEFINE:([Expr1005]=SUM([Expr1007]))) 
       |--Compute Scalar(DEFINE:([Expr1004]=CONVERT(nchar(3),[mssqlsystemresource].[sys].[spt_values].[type],0), [Expr1007]=CONVERT(bigint,[mssqlsystemresource].[sys].[spt_values].[number],0))) 
         |--Index Scan(OBJECT:([mssqlsystemresource].[sys].[spt_values].[ix2_spt_values_nu_nc])) 

Dies ist sehr wahrscheinlich, wie alle anderen DBMS so gut funktionieren, zumindest die wichtigsten auf Berücksichtigung heißt PostgreSQL, Sybase, Oracle, DB2, Firebird, MySQL.