如何使 PL/pgSQL 中的查询运行时与控制台查询运行时一样快?

Oxf*_*ist 3 postgresql performance plpgsql query-performance

基本上我想将查询结果分配给自定义类型属性。但是我注意到直接从 PostgreSQL 控制台查询大约需要 0.071 毫秒,并且在几次调用后函数内部为 0.400 毫秒和 0.170 毫秒。explain analyze甚至显示了第一种情况下索引的使用情况,但没有显示第二种情况。

这就是我正在做的。

CREATE OR REPLACE FUNCTION fun_isliked(
    par_client client.id%type,
    par_feed feed.id%type
)
RETURNS boolean
AS
$$
BEGIN
    RETURN (
        EXISTS(
            SELECT
                1
            FROM
                feedlike fl
            WHERE
                fl.client = par_client
                AND fl.feed = par_feed
                AND fl.state = 1
        )
    );
END;
$$ LANGUAGE plpgsql STABLE;
Run Code Online (Sandbox Code Playgroud)

以下是上述explain analyze两种情况的输出:

postgres=# explain analyze select exists (select 1 from feedlike where client = 13 and feed = 68 and state = 1);
                                                                  QUERY PLAN                                                                  
----------------------------------------------------------------------------------------------------------------------------------------------
 Result  (cost=8.30..8.31 rows=1 width=0) (actual time=0.037..0.037 rows=1 loops=1)
   InitPlan 1 (returns $0)
     ->  Index Scan using feedlike_client_feed_unique on feedlike  (cost=0.28..8.30 rows=1 width=0) (actual time=0.034..0.034 rows=1 loops=1)
           Index Cond: ((client = 13) AND (feed = 68))
           Filter: (state = 1)
 Total runtime: 0.086 ms

postgres=# explain analyze select * from fun_isliked(13, 68);
                                                QUERY PLAN                                                
----------------------------------------------------------------------------------------------------------
 Function Scan on fun_isliked  (cost=0.25..0.26 rows=1 width=1) (actual time=0.398..0.398 rows=1 loops=1)
 Total runtime: 0.416 ms
Run Code Online (Sandbox Code Playgroud)

为了有效地在函数内部获得相同的运行时,可能的解决方法是什么?甚至有可能吗?另外,我正在运行 PostgreSQL 9.3。

我发现SO中的这个问题有我所需要的,但是在我尝试了所选答案中的所有内容并且没有成功减少运行时间后,我决定提出一个新问题。

Erw*_*ter 5

房间里的大象是头顶的功能。当调用函数而不是原始 SQL 时,Postgres 需要在系统目录中查找函数(可能在函数重载的情况下选择最佳匹配)并考虑函数的设置。然后是函数调用本身的开销。这增加了很小的间接成本。

这仅对于像您的示例这样的非常简单的查询才真正重要 - 应该使用普通的 SQL 函数来实现。您仍然会遇到 SQL 函数的一些(微小的)函数开销,但如果它很简单SELECT并且满足一些先决条件,则可以“内联”它

像往常一样,重复调用从填充的缓存中获益。在 plpgsql 函数的情况下,它也可能在一些(通常是 5 次)调用之后开始使用通用计划,如果这看起来很有希望的话。

考虑有关 pgsql-general 的相关讨论

plpgsql 函数内代码的查询计划

你想知道:

explain analyze 甚至在第一种情况下显示了索引的使用,但在第二个 [plpgsql 函数] 中没有显示。

plpgsql 函数对于查询规划器来说是黑盒子,它不检查函数的内容。它们充当优化障碍。与 SQL 函数不同,它们的内容不能在外部查询中内联。

这就是为什么EXPLAIN ANALYZE不显示plpgsql 函数内部发生的事情的原因,因此您看不到索引扫描。索引(最有可能)仍在使用。您可以使用附加模块auto_explain查看函数内 SQL 代码的查询计划。有关详细信息,请考虑此相关问题的答案: