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

Postgres Function - SQLs in Loop really a prepared Statement?

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

现在我发现性能很慢,但前提是我在更改参数时执行了更多 SQLs 的循环。

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

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;

因此,如果我比较只执行循环内的 select 与 Postgres 和 Firebird 所花费的时间,那么 Postgres 通常比 Firebird 快一点。但是如果循环运行 100 或 1000 或 10000 次,则比 Firebird 存储过程的时间要快得多。当我比较 Postgres 中的时间时,似乎如果循环运行 10 次,它需要的时间比 1 行长 10 倍,如果它运行 1000 次,则需要 1000 倍的时间......如果它真的是一个准备好的语句,那不应该,对吧?

我还检查了其他问题,例如将内存设置设置得较高,将语句 "return next" 留在外面,因为我读到这也会导致性能问题.... 它也与 "returns table" 表达式无关。如果我把它排除在外,它也需要同样的时间.. 到目前为止没有任何效果...

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

我是不是漏掉了什么?

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

但它也可能会重用执行计划,有时这对您不利。 运行 您在 EXECUTE 语句中的查询可以提供更好的性能,尽管每次都需要重新准备它。

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

终于明白了...这是一个索引问题,但对我来说并不完全有意义...

因为如果我在函数外执行 SQL,它们甚至比使用 Indizes 的 Firebird 还要快。现在它们在 Postgres 的函数之外,速度甚至是以前的两倍,而且这些函数现在运行起来也非常快。也比 Firebird 更快...

之所以我也没有考虑到这一点,是因为在 Firebird 中,外键也可以用作 indizes。我预计在 Postgres 中会是一样的,但事实并非如此......

真应该早点考虑,也是因为 Frank 和 Pavel 的评论。

谢谢大家...