在同一查询中使用SUM的结果

时间:2014-03-07 07:18:08

标签: sql postgresql aggregate-functions postgresql-performance

SELECT 
business_period,
SUM(transaction.transaction_value) AS total_transaction_value,
SUM(transaction.loss_value) AS total_loss_value,
(total_transaction_value - total_loss_value) AS net_value
FROM transaction
GROUP BY business_period

上述内容不起作为total_transaction_value,而total_loss_value不在transaction表中。有没有办法让这个查询有效?

注意:此查询涉及5亿行,因此需要高效。

问题:
一些答案表明SUM(transaction.transaction_value) - SUM(transaction.loss_value)被缓存,并且不需要再次计算,而其他人则建议我应该作为派生表/子查询来避免重复计算。有人能指出可以解决意见分歧的事情吗?

我正在使用postgres 9.3。

解答:

我想在这里引用erwin的评论:

I ran a quick test with 40k rows and the winner was the plain version without subquery. CTE was slowest. So I think my first assumption was wrong and the query planner understands not to calculate the sums repeatedly (makes sense, too). I have seen different results with more complex expressions in the past. The planner does get smarter with every new version

4 个答案:

答案 0 :(得分:1)

使用:

SELECT 
business_period,
SUM(transaction.transaction_value) AS total_transaction_value,
SUM(transaction.loss_value) AS total_loss_value,
(SUM(transaction.transaction_value) - SUM(transaction.loss_value)) AS net_value
FROM transaction
GROUP BY business_period

答案 1 :(得分:0)

再次使用sum

SELECT 
business_period,
SUM(transaction.transaction_value) AS total_transaction_value,
SUM(transaction.loss_value) AS total_loss_value,
(SUM(transaction.transaction_value) - SUM(transaction.loss_value)) AS net_value
FROM transaction
GROUP BY business_period

答案 2 :(得分:0)

只需明确重申SUM(我相信它们只计算一次):

SELECT 
  business_period,
  SUM(transaction.transaction_value) AS total_transaction_value,
  SUM(transaction.loss_value) AS total_loss_value,
  SUM(transaction.transaction_value) - SUM(transaction.loss_value) AS net_value
FROM transaction
GROUP BY business_period

或者你可以使用派生表子查询,如果上面没有隐式地执行它,它应该强制它只计算一次 - 尽管可能会有一些额外的开销,具体取决于优化器看到的内容:

SELECT business_period,
  total_transaction_value,
  total_loss_value,
  (total_transaction_value - total_loss_value) AS net_value
FROM
(
    SELECT 
       business_period,
       SUM(transaction.transaction_value) AS total_transaction_value,
       SUM(transaction.loss_value) AS total_loss_value,
    FROM transaction
    GROUP BY business_period
) x

答案 3 :(得分:0)

使用子查询以避免重复计算:

SELECT *, total_transaction_value - total_loss_value AS net_value
FROM  (
   SELECT business_period
        , SUM(transaction_value) AS total_transaction_value
        , SUM(loss_value)        AS total_loss_value
   FROM   transaction
   GROUP  BY 1
   ) sub;

CTE (common table expresson)实际强制这一点,因为CTE构成优化障碍。对于像这样的简单情况,子查询通常更快。当折叠子查询更快时,Postgres会更清楚。