我有一个简单的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子句,但我不确定它的行为是否与下面的连接解决方案相同。
答案 0 :(得分:0)
鉴于您的原始查询,我认为这可能是最便宜的方式,每次f
和join
结果只进行一次计算:
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;
我不知道编写自定义聚合函数如何帮助除非聚合函数隐藏已经计算的值。将为原始表中的每一行调用聚合函数,而不是后聚合结果中的每一行。