用 plpgsql 编写的函数调用的 Postgres 查询计划

Has*_*yed 23 postgresql performance plpgsql functions

它使用的时候可能pgadmin还是plsql获得查询计划的搁置了内部执行SQL语句ü SER d efined ˚F油膏(UDF)使用EXPLAIN。那么我如何掌握 UDF 的特定调用的查询计划呢?我看到 UDF 抽象为F()pgadmin 中的单个操作。

我查看了文档,但找不到任何内容。

目前我正在提取语句并手动运行它们。但这不会减少大型查询。

例如,考虑下面的 UDF。这个 UDF,即使它能够打印出它的查询字符串,也不能使用复制粘贴,因为它有一个本地创建的临时表,当你粘贴和执行它时它不存在。

CREATE OR REPLACE FUNCTION get_paginated_search_results(
    forum_id_ INTEGER,
    query_    CHARACTER VARYING,
    from_date_ TIMESTAMP WITHOUT TIME ZONE DEFAULT NULL,
    to_date_ TIMESTAMP WITHOUT TIME ZONE DEFAULT NULL,
    in_categories_ INTEGER[] DEFAULT '{}')
RETURNS SETOF post_result_entry AS $$
DECLARE
    join_string CHARACTER VARYING := ' ';
    from_where_date CHARACTER VARYING := ' ';
    to_where_date CHARACTER VARYING := ' ';
    query_string_ CHARACTER VARYING := ' ';
BEGIN
    IF NOT from_date_ IS NULL THEN
        from_where_date := ' AND fp.posted_at > ''' || from_date_ || '''';
    END IF;

    IF NOT to_date_ IS NULL THEN
        to_where_date := ' AND fp.posted_at < ''' || to_date_ || '''';
    END IF;

    CREATE LOCAL TEMP TABLE un_cat(id) ON COMMIT DROP AS (select * from unnest(in_categories_)) ;

    if in_categories_ != '{}' THEN
        join_string := ' INNER JOIN forum_topics ft ON fp.topic_id = ft.id ' ||
        ' INNER JOIN un_cat uc ON uc.id = ft.category_id ' ;
    END IF;

    query_string_ := '
    SELECT index,posted_at,post_text,name,join_date,quotes
    FROM forum_posts fp
    INNER JOIN forum_user fu ON
    fu.forum_id = fp.forum_id AND fu.id = fp.user_id' ||
        join_string
    ||
    'WHERE fu.forum_id = ' || forum_id_ || ' AND
    to_tsvector(''english'',fp.post_text) @@ to_tsquery(''english'','''|| query_||''')' || 
        from_where_date || 
        to_where_date
    ||';';

    RAISE NOTICE '%', query_string_ ;

    RETURN QUERY
    EXECUTE query_string_;
END;
$$ LANGUAGE plpgsql;
Run Code Online (Sandbox Code Playgroud)

rfu*_*sca 19

您应该能够使用auto-explain。打开它并

SET auto_explain.log_min_duration = 0;

并且您应该在日志中获取该会话中运行的所有语句的计划。

可能还想设置

SET auto_explain.log_analyze = true; 但是您基本上会双倍运行所有内容 - 一次是“真实”,一次是解释分析。在非计时性能测试阶段,此输出可能比单独的 EXPLAIN 计划有用得多,因为它提供了实际发生的计划。

  • 正如@Erwin 在下面指出的那样,您也应该设置 auto_explain.log_nested_statements = ON。 (4认同)

Erw*_*ter 18

我除了@rfusca 的建议:plpgsql 函数中的 SQL 语句被视为嵌套语句,您需要设置额外的 Parameter auto_explain.log_nested_statements

与其他一些扩展不同,您不必CREATE EXTENSION为这个扩展而运行。只需将其动态加载到您的会话中LOAD。为此,您必须是 超级用户
您的会话可能如下所示:

LOAD 'auto_explain';
SET auto_explain.log_min_duration = 1; -- exclude very fast trivial queries
SET auto_explain.log_nested_statements = ON; -- statements inside functions
-- SET auto_explain.log_analyze = ON; -- get actual times, too
SELECT * FROM get_paginated_search_results(...);
Run Code Online (Sandbox Code Playgroud)

可能会产生大量的日志输出。
当前的auto_explain手册。当 PostgreSQL 8.4 引入时,
Depesz 写了一篇关于它博客文章