Plan zapytań Postgres wywołania funkcji napisany w plpgsql

19

Jest to możliwe przy użyciu pgadminalbo plsqlsię trzymać planu zapytań do SQL instrukcji wykonywanych Wewnątrz u ser d efined f namaszczenie (UDF), używając EXPLAIN. Jak więc uzyskać plan zapytań dla konkretnego wywołania UDF? Widzę, jak UDF jest abstrahowany w pojedynczej operacji F()w pgadmin.

Przejrzałem dokumentację, ale nic nie znalazłem.

Obecnie wyciągam wyciągi i uruchamiam je ręcznie. Ale to nie zmniejszy tego w przypadku dużych zapytań.

Rozważmy na przykład UDF poniżej. Ten UDF, mimo że ma możliwość wydrukowania ciągu zapytania, nie będzie działał z kopiowaniem-wklejaniem, ponieważ ma lokalną tabelę tymczasową, która nie istnieje podczas wklejania i wykonywania.

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;
Hassan Syed
źródło

Odpowiedzi:

16

Powinieneś być w stanie korzystać z automatycznego wyjaśniania . Włącz i

SET auto_explain.log_min_duration = 0;

i powinieneś dostać plany do swojego dziennika dla wszystkich instrukcji uruchamianych w tej sesji.

Państwo może również chcesz ustawić

SET auto_explain.log_analyze = true; ale zasadniczo uruchomisz wszystko podwójnie - raz dla „prawdziwej” i raz dla WYJAŚNIENIA ANALIZY. Podczas fazy testowania wydajności bez pomiaru czasu dane wyjściowe mogą być znacznie bardziej przydatne niż same plany EXPLAIN, ponieważ zapewniają rzeczywisty plan.

rfusca
źródło
4
Jak wskazuje @Erwin poniżej, powinieneś również ustawić auto_explain.log_nested_statements = ON.
rfusca
Dzięki, to załatwiło sprawę. szkoda, że ​​ta funkcjonalność nie jest dostępna przez GUI.
Hassan Syed
@ rfusca w zasadzie wszystko uruchomisz podwójnie, gdzie jest na to dowód? Niektóre eksperymenty nie wykazały tego zachowania.
Sebastian Dressler
Zdaj sobie sprawę, że w tym momencie odwołuje się do 7-letniej bazy danych. Prawdopodobnie już tak nie działa, jeśli nie widzisz takich samych wyników.
rfusca
16

Uzupełniam radę @ rfusca: instrukcje SQL wewnątrz funkcji plpgsql są uważane za zagnieżdżone i należy ustawić dodatkowy parametr auto_explain.log_nested_statements.

W przeciwieństwie do niektórych innych rozszerzeń, nie musisz biegać CREATE EXTENSIONpo to. Wystarczy załadować go dynamicznie do sesji za pomocą LOAD. Twoja sesja może wyglądać następująco:

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

Może produkować dużo danych wyjściowych dziennika. Aktualny podręcznik na auto_explain. Depesz napisał na ten temat artykuł na blogu, gdy został wprowadzony wraz z PostgreSQL 8.4.

Erwin Brandstetter
źródło
+1 - minęło tak dużo czasu, że zapomniałem o ustawieniu linii
log_nested_statements
3
W każdym razie zasługujesz na uznanie za odpowiednie narzędzie.
Erwin Brandstetter,
Mam bazę danych Postgres dotyczącą usługi zarządzanej Amazon (RDS), do której LOAD 'auto_explain';zwraca ERROR: access to library "auto_explain" is not allowed. Co w takim razie? Osiągnąłem pewien sukces włamując się do moich funkcji, return query explain select …ale jest to pracochłonne i powolne.
najszerszy