2012-10-13 4 views
5

Esiste uno standard per l'implementazione di SQL per più chiamate alla stessa funzione di aggregazione nella stessa query?Esiste uno standard per il calcolo della funzione di aggregazione SQL?

Ad esempio, si consideri il seguente esempio, sulla base di uno schema di esempio popolare:

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

Presumibilmente, ci vuole tempo di calcolo per calcolare il valore di SUM (OrderPrice). Questo costo è sostenuto per ogni riferimento alla funzione aggregata o il risultato è archiviato per una determinata query?

Oppure, non esiste uno standard per l'implementazione del motore SQL per questo caso?

risposta

3

Anche se ho lavorato con molti DBMS diversi, mostrerò solo il risultato di provarlo su SQL Server. Considera questa query, che include persino un CAST nell'espressione. Esaminando il piano di query, l'espressione sum(cast(number as bigint)) viene eseguita solo una volta, che è definita come DEFINE:([Expr1005]=SUM([Expr1006])).

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])) 

Esso non può essere molto evidente in precedenza, dal momento che non mostra il risultato SELECT, quindi ho aggiunto un *10 alla query di seguito. Si noti che ora include un passaggio aggiuntivo DEFINE:([Expr1006]=[Expr1005]*(10)) (passaggi eseguiti dal basso verso l'alto) che dimostra che la nuova espressione lo richiedeva per eseguire un calcolo aggiuntivo. Tuttavia, anche questo è ottimizzato, in quanto non ricalcola l'intera espressione - semplicemente, sta prendendo Expr1005 e moltiplicandolo per 10!

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])) 

questo è molto probabile che come tutti gli altri DBMS funzionano così, almeno considerando le principali quelli cioè PostgreSQL, Sybase, Oracle, DB2, Firebird, MySQL.