План запитів постгресів виклику функції, написаного в plpgsql


19

Це можливо при використанні pgadminабо plsqlсхопити план запиту для SQL виконаного оператора Всередині у сер д efined е соборування (UDF) , використовуючи EXPLAIN. Тож як я можу отримати план запитів для певної виклику UDF? Я бачу, що АДС абстрагується в одній операції F()в pgadmin.

Я переглянув документацію, але нічого не зміг знайти.

Наразі я витягую твердження і виконую їх вручну. Але це не збирається вирішувати для великих запитів.

Наприклад, розглянемо нижче АДС. Цей 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, оскільки він забезпечує, який план насправді відбувся.


4
Як @Erwin вказує нижче, слід також встановити auto_explain.log_nested_statements = ON.
rfusca

Дякую, що зробив трюк. прикро, що ця функціональність недоступна через GUI.
Хассан Сид

@rfusca ти по суті будеш запускати все вдвічі, де це підтвердження? У деяких експериментах я не виявляв такої поведінки.
Себастьян Dressler

Зрозумійте це, посилаючись на 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 …але це копітко і повільно.
найкраще
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.