如何延迟postgres中的昂贵计算直到最后的步骤

时间:2014-01-21 14:33:49

标签: sql postgresql group-by aggregate-functions postgresql-9.1

我有一个简单的postgres 9.1查询,其中包含非常昂贵的计算:

SELECT a, b, sum(c), very_expensive_calculation(f)
FROM my_table
GROUP BY a, b, f

函数very_expensive_calculation()是我的自定义函数(非聚合),它在幕后运行值的递归求和,因此需要一段时间。之所以出现此问题,是因为my_table中存在许多重复项,因为它非常非规范化,因此当它应该只在不同的值上运行时,每行运行一次。我尝试了以下操作来对预先分组的值运行该函数:

SELECT a, b, c_sum, very_expensive_calculation(f)
FROM (
  SELECT a, b, sum(c) c_sum, f
  FROM my_table
  GROUP BY a, b, f
) pre_group

这减少了very_expensive_calculations()的运行次数,因为如果原始查询包含100行但分组只包含10行,那么我的执行次数减少了90%。然而,这很麻烦,并且还会遇到其他问题(有很多标准和专栏,我没有展示自定义逻辑,而且他们正遭受这种黑客攻击)。

我可以运行第一个查询,但是延迟very_expensive_calculation()来运行已经分组的 f 值,可能是通过将very_expensive_function()声明为聚合?

编辑(@gordon linoff):以下内容与下面提到的答案相同吗?

WITH fvec AS (
 select f, very_expensive_calculation(f) as vec
 from (select distinct f from my_table) mt
)
Select a, b, sum(c), fvec.vec
from my_table agg inner join fvec on agg.f = fvec.f
group by a, b, fvec.vec

我们自动生成的代码可以轻松地执行WITH子句,但我不确定它的行为是否与下面的连接解决方​​案相同。

1 个答案:

答案 0 :(得分:0)

鉴于您的原始查询,我认为这可能是最便宜的方式,每次fjoin结果只进行一次计算:

select agg.*, fvec.fec
from (SELECT a, b, sum(c) as sumc
      FROM my_table
      GROUP BY a, b, f
     ) agg join
     (select f, very_expensive_calculation(f) as vec
      from (select distinct f from my_table) mt
     ) fvec
     on agg.f = fvec.f;

我不知道编写自定义聚合函数如何帮助除非聚合函数隐藏已经计算的值。将为原始表中的每一行调用聚合函数,而不是后聚合结果中的每一行。