PostgreSQL pl/pgSQL函数调用是否会引入性能成本?

PostgreSQL pl/pgSQL函数调用是否会引入性能成本?,postgresql,Postgresql,这篇文章从一个简单的问题开始,我最初的搜索没有找到答案。考虑以下功能: CREATE OR REPLACE FUNCTION sys.return_jsonb(return_code shared.return_code, return_msg shared.return_msg) RETURNS jsonb LANGUAGE sql AS $function$ SELECT format('{"result": "%s","message&

这篇文章从一个简单的问题开始,我最初的搜索没有找到答案。考虑以下功能:

CREATE OR REPLACE FUNCTION sys.return_jsonb(return_code shared.return_code, return_msg shared.return_msg)
RETURNS jsonb LANGUAGE sql
AS $function$
  SELECT format('{"result": "%s","message": "%s"}', return_code, return_msg)::jsonb; -- AS result;
$function$
;
考虑两种情况:

RETURN (SELECT sys.return_jsonb(success_code, success_msg))


问题:函数调用是否会比内联版本更昂贵?

我突然想到,凭我自己的经验回答这个问题并不困难。然而,结果是,我发现自己回答了两个问题:一个是我提出的问题,另一个是其他发表评论的人提出的问题

首先,我的问题是:

CREATE OR REPLACE FUNCTION sys.return_jsonb_tester(return_code shared.return_code, return_msg shared.return_msg)
RETURNS jsonb
 LANGUAGE plpgsql
AS $function$
declare
  return_jsonb jsonb;
BEGIN
  FOR i IN 1 .. 100000 LOOP
    -- v1
    --SELECT sys.return_jsonb(return_code, return_msg) INTO return_jsonb;

    -- v2
    --SELECT format('{"result": "%s","message": "%s"}', return_code, return_msg)::jsonb INTO return_jsonb;
  END LOOP;
  RETURN return_jsonb;
END ;
$function$
;
函数调用(v1)大约花费了0.2秒。 内联版本(v2)大约需要0.2秒

基本上没有区别。因此,我可以尽我所能免费提取出样板代码

我将我的问题和我自己的答案分享给下一个可能会发现这个结果信息丰富的人

但我们的故事并没有就此结束

在我的OP中,我对callout例程sys.return_jsonb()使用了
语言plpgsql
。事实上,在这一点上,我发现callout比inline稍微贵一点,但还不足以引起关注。然而,一个没有名字的注释建议我改用
语言sql

我尝试过这个建议。从大门出来时效率非常低——慢了几个数量级。所以我选择了
语言plpgsql

然后,另一位评论员劳伦斯·阿尔贝建议重做,这次没有一成不变。所以我又做了一次实验。这里提供的名称暗示了四种口味。时间显示:

SELECT sys.sql_immutable('00001', 'It''s awesome!'); -- 1.10s
SELECT sys.sql_not_immutable('00001', 'It''s awesome!'); -- 0.19s
SELECT sys.plpgsql_immutable('00001', 'It''s awesome!'); -- 0.24s
SELECT sys.plpgsql_not_immutable('00001', 'It''s awesome!'); -- 0.26s
因此,所有这一切的结果是,由于这些评论,我确实使用了callout,但是使用了理想的策略,即使用
语言sql
,而不是使用
不可变的

当我完成时,调用基本上与内联的速度相同。最后的结果就是我在回答我自己的问题时公布的。使用详图索引不需要任何成本。Laurenz指出,“实际上,您是在以这种方式内联,因为PostgreSQL将在适当的时候内联SQL函数,而在这种情况下,删除不可变项是适当的。”这些数字说明了相同的情况,因此这是有意义的


具有讽刺意味的是,我的OP主题行询问了
不可变
函数的调用,但我现在已经修改了。说到做到,最好的选择是调用一个“可变”SQL函数。

由于输入是恒定的,
格式
是稳定的
,所以在事务中,也就是在整个循环中,应该只评估一次,就像
不可变的
函数一样。如果在两个事务之间使用相同的输入调用
不可变
函数,则它应该比使用
格式
更快。如果输入一直在变化,则所需的时间应该差不多相同(函数的开销可能很小),而
语言sql
函数的开销可能更大efficient@a_horse_with_no_name也许我做错了什么,但是我尝试了你的建议,用了1.3秒的时间通过
语言sql
完成了0.3秒后通过
语言plpgsql
可以完成的工作。我将在另一个答案中发布这个结果。这显示了完全相反的结果,我想知道为什么简单的计算行为不同于调用format(),我不知道。我总是可能遗漏了一些东西,但您可以看到我运行的代码。如下所述,在从例程中删除IMMUTABLE(根据Laurenz的建议)后,您的直觉和期望证明是准确的。
SELECT sys.sql_immutable('00001', 'It''s awesome!'); -- 1.10s
SELECT sys.sql_not_immutable('00001', 'It''s awesome!'); -- 0.19s
SELECT sys.plpgsql_immutable('00001', 'It''s awesome!'); -- 0.24s
SELECT sys.plpgsql_not_immutable('00001', 'It''s awesome!'); -- 0.26s