Postgres函数 - 循环中的SQL真的是一个准备好的语句吗?

时间:2015-01-13 14:34:04

标签: performance function postgresql loops plpgsql

现在我正在为我的公司从Firebird 2.5迁移到Postgres 9.4,我还将存储过程从Firebird转换为函数到Postgres ......

现在我发现性能非常慢,但只有在循环中我执行更多的SQL而不改变参数。

所以例如它看起来像这样(我把它简化为必要的东西)

CREATE OR REPLACE FUNCTION TEST
(TEST_ID BigInt) returns TABLE(NAME VARCHAR)
AS $$
declare _tmp bigint;
begin
for _tmp in select id from test 
loop
-- Shouldn't the following SQL work as a Prepared Statement?
for name in select label
from test2
where id = _tmp
loop
return next;
end loop;

end loop;

end; $$
LANGUAGE plpgsql;

因此,如果我比较使用Postgres和Firebird执行循环内部选择所需的时间,那么Postgres通常比Firebird快一点。但是如果循环运行的速度比Firebird存储过程的时间长100或1000或10000倍要快得多。当我比较Postgres中的时间时,它看起来好像如果循环运行10次它需要10倍然后1行,如果它运行1000次需要1000倍......这应该不是如果它真的是一个准备好的声明,对吗?

我还检查了其他问题,例如将内存设置设置为高,将语句“return next”留下,因为我读到这可能会导致性能问题.... 它也与“返回表”表达式无关。如果我把它留下来也需要同样的时间.. 到目前为止没有任何工作......

当然这个简单的例子也可以用一个SQL解决,但我迁移的函数要复杂得多,我不想把整个函数改成新的东西(如果可能的话)......

我错过了什么吗?

2 个答案:

答案 0 :(得分:1)

PL / pgSQL跨函数调用重用已准备好的查询;每次会议只会产生一次准备费用。因此,除非您在每次测试之间重新连接,否则预计会有线性执行时间。

但它也可能会重复使用执行计划,有时这对您没有好处。在EXECUTE语句中运行查询可以提供更好的性能,尽管每次都重新进行重写。

有关详细信息,请参阅PL/pgSQL documentation

答案 1 :(得分:0)

终于搞定了......这是一个索引问题,但对我来说并不完全合理......

因为如果我在函数之外执行SQL,它们甚至比具有Indizes的Firebird更快。现在他们在Postgres的功能之外甚至比之前快两倍,现在功能也非常快。也像Firebird一样快......

我之所以不考虑这个原因,是因为在Firebird中,外键也可以作为indizes使用。我预计在Postgres会是一样的,但它不是......

由于弗兰克和帕维尔的评论,本来应该真的考虑过。

感谢所有人......