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


19

它使用的时候可能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;

Answers:


16

您应该能够使用auto-explain。打开它,然后

SET auto_explain.log_min_duration = 0;

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

可能还想设置

SET auto_explain.log_analyze = true; 但实际上,您将使所有内容都翻倍-一次是“真实”,一次是EXPLAIN ANALYZE。在非计时性能测试阶段,此输出可能比单独的EXPLAIN计划有用得多,因为它提供了实际发生的计划。


4
正如@Erwin在下面指出的那样,您还应该将auto_explain.log_nested_statements设置为ON。
rfusca 2012年

谢谢,做到了。遗憾的是,该功能无法通过GUI访问。
哈桑·赛义德

@rfusca实际上,将使所有内容翻倍运行,那里的证明在哪里?我没有进行一些实验,没有显示此行为。
塞巴斯蒂安·德莱斯特勒

意识到这是在参考一个已有7年历史的数据库。如果您没有看到相同的结果,那么它可能不再那样工作。
rfusca

16

除了@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(...);

可能会产生很多日志输出。
当前的auto_explain手册。
Depesz 在PostgreSQL 8.4中引入有关它博客文章


+1-已经很久了,我忘记了需要设置log_nested_statements行
rfusca,2012年

3
无论如何,您应该得到正确工具的荣誉。
Erwin Brandstetter,2012年

我在Amazon的托管服务(RDS)上有一个postgres数据库,该数据库LOAD 'auto_explain';返回ERROR: access to library "auto_explain" is not allowed。那样的话 我在破解功能方面取得了一些成功,return query explain select …但这既费力又缓慢。
华丽的
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.