План запросов Postgres для вызова функции, написанный на plpgsql

19

Это возможно при использовании pgadminили plsqlухватить план запроса для SQL выполненного оператора Внутри у сер д efined е соборования (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;
Хасан Сайед
источник

Ответы:

16

Вы должны быть в состоянии использовать автоматическое объяснение . Включи и

SET auto_explain.log_min_duration = 0;

и вы должны получить планы в своем журнале для всех операторов, запущенных в этом сеансе.

Вы могли бы также хотеть набор

SET auto_explain.log_analyze = true; но вы, по сути, будете выполнять все дважды - один раз для «реального» и один раз для «ОБЪЯСНИТЬ АНАЛИЗ». На несвоевременной фазе тестирования производительности эти выходные данные могут быть гораздо более полезными, чем только планы EXPLAIN, так как они показывают, какой план действительно имел место.

rfusca
источник
4
Как указывает @Erwin ниже, вы должны также установить auto_explain.log_nested_statements = ON.
rfusca
Спасибо, это сработало. Жаль, что эта функция не доступна через графический интерфейс.
Хасан Сайед
@ rfusca, ты по сути делаешь все дважды, где доказательства для этого? В некоторых экспериментах я не показывал такого поведения.
Себастьян Дресслер
Поймите, что это ссылка на 7-летнюю базу данных на данный момент. Скорее всего, это больше не работает, если вы не видите те же результаты.
rfusca
16

В дополнение к совету @ rfusca: операторы SQL внутри функций plpgsql считаются вложенными, и вам необходимо установить дополнительный параметр 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
3
В любом случае, вы заслуживаете признательности за использование правильного инструмента.
Эрвин Брандстеттер
У меня есть база данных postgres на управляемой службе Amazon (RDS), для которой LOAD 'auto_explain';возвращается ERROR: access to library "auto_explain" is not allowed. Что в таком случае? У меня был некоторый успех во взломе моих функций, return query explain select …но это кропотливо и медленно.
шикарная