今天, IF club 群里发了一个问题: 如何让PostgreSQL自定义聚合函数的finalfunc仅执行一次?
在我的碳基神经元还停留在过去式, 记忆也出现了混乱, 也没有去看最新文档(没有使用RAG)的情况下, 非常自信的回答了:
“应该是该聚合函数没有实现 parallel (PS: 其实是需要实现 COMBINEFUNC, 将不同worker的中间结果进行合并的函数), 所以会多次调用finalfunc(PS: 这是错误的). 只要在定义agg func时设置为 parallel unsafe 即可!”
大错特错, 我蠢到家了. AI 狠狠的给了我一巴掌.
PS: 这些是我之前写的一些PG agg相关的文章, 仅供参考, 如果你想知道聚合的内部运算逻辑, 可以看一下:
AI 的牛逼在于它的神经元比我多多了, 同时它训练的素材也比我多多了, 并且它还有基于实时资料库的RAG, 我在AI面前就是弱鸡!
要让自定义聚合函数的finalfunc只执行一次,需要从聚合状态共享和finalfunc属性两个方面进行控制。
在创建聚合函数时指定finalfunc为只读模式:
CREATE AGGREGATE my_aggregate(input_type) (
SFUNC = transition_function,
STYPE = transition_type,
FINALFUNC = final_function,
FINALFUNC_MODIFY = READ_ONLY
);
FINALFUNC_MODIFY = READ_ONLY表示finalfunc不修改其参数,这是默认值(除了有序集合聚合) 。
通过设置shareable = false来防止多个聚合共享同一个状态值 :
// 在聚合函数的内部实现中
peragg->shareable = false;
在finalfunc中添加状态检查逻辑,确保只执行一次:
Datum
my_finalfunc(PG_FUNCTION_ARGS)
{
static bool executed = false;
if (executed)
PG_RETURN_NULL();
// 执行实际的final逻辑
executed = true;
// ... 你的处理逻辑
PG_RETURN_DATUM(result);
}
PostgreSQL的聚合执行流程中,finalfunc在finalize_aggregate函数中被调用 :
array_agg_finalfn的注释所示-- 转换函数
CREATEFUNCTION my_transfn(internal, integer)
RETURNS internal AS'MODULE_PATHNAME'LANGUAGE C;
-- 最终函数
CREATEFUNCTION my_finalfn(internal)
RETURNSintegerAS'MODULE_PATHNAME'LANGUAGE C IMMUTABLE;
-- 创建聚合,确保finalfunc只执行一次
CREATEAGGREGATE my_agg(integer) (
SFUNC = my_transfn,
STYPE = internal,
FINALFUNC = my_finalfunc,
FINALFUNC_MODIFY = READ_ONLY,
PARALLEL = SAFE
);
可以使用测试用例验证finalfunc的执行次数 :
-- 在transfn和finalfn中添加NOTICE来观察调用次数
CREATEFUNCTION test_transfn(state int4, n int4) RETURNS int4 AS $$
BEGIN
RAISENOTICE'transfn called with %', n;
RETURN COALESCE(state, 0) + n;
END;
$$ LANGUAGE plpgsql;
CREATEFUNCTION test_finalfn(state int4) RETURNS int4 AS $$
BEGIN
RAISENOTICE'finalfn called with %', state;
RETURN state;
END;
$$ LANGUAGE plpgsql;
FINALFUNC_MODIFY有三个选项:READ_ONLY、SHAREABLE、READ_WRITEAggInfo结构中控制相关代码:
doc/src/sgml/ref/create_aggregate.sgml
<term><literal>FINALFUNC_MODIFY</literal> = { <literal>READ_ONLY</literal> | <literal>SHAREABLE</literal> | <literal>READ_WRITE</literal> }</term>
<listitem>
<para>
This option specifies whether the final function is a pure function
that does not modify its arguments. <literal>READ_ONLY</literal> indicates
it does not; the other two values indicate that it may change the
transition state value. See <xref linkend="sql-createaggregate-notes"/>
below for more detail. The
default is <literal>READ_ONLY</literal>, except for ordered-set aggregates,
for which the default is <literal>READ_WRITE</literal>.
</para>
src/include/executor/nodeAgg.h
* "shareable" is false if this agg cannot share state values with other
* aggregates because the final function is read-write.
*/
bool shareable;
AI面前, 我就是小蚂蚁!
你怎么看? 欢迎留言