Postgres-Abfrageplan eines in plpgsql geschriebenen Funktionsaufrufs

19

Es ist möglich , wenn die Verwendung pgadminoder plsqlein Halten eines Abfrageplan für eine SQL - Anweisung in einem ausgeführt zu bekommen u ser d efined f Salbung (UDF) verwenden EXPLAIN. Wie erhalte ich den Abfrageplan für einen bestimmten Aufruf einer UDF? Ich sehe die UDF in einer einzigen Operation F()in pgadmin abstrahiert.

Ich habe mir die Dokumentation angesehen, aber nichts gefunden.

Momentan ziehe ich die Anweisungen heraus und führe sie manuell aus. Dies ist jedoch nicht für große Abfragen geeignet.

Betrachten Sie beispielsweise die folgende UDF. Diese UDF kann zwar die Abfragezeichenfolge ausdrucken, funktioniert jedoch nicht mit dem Kopieren und Einfügen, da eine lokal erstellte temporäre Tabelle vorhanden ist, die beim Einfügen und Ausführen nicht vorhanden ist.

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
quelle

Antworten:

16

Sie sollten in der Lage sein, automatisch zu erklären . Schalten Sie es ein und

SET auto_explain.log_min_duration = 0;

und Sie sollten die Pläne für alle in dieser Sitzung ausgeführten Anweisungen in Ihr Protokoll aufnehmen.

Vielleicht möchten Sie auch festlegen

SET auto_explain.log_analyze = true; Aber Sie werden im Grunde alles doppelt ausführen - einmal für "echt" und einmal für "EXPLAIN ANALYZE on". Während einer nicht zeitgesteuerten Leistungstestphase kann diese Ausgabe viel nützlicher sein als EXPLAIN-Pläne allein, da sie den tatsächlichen Plan enthält.

rfusca
quelle
4
Wie @Erwin weiter unten ausführt, sollten Sie auch auto_explain.log_nested_statements = ON setzen.
Rfusca
Danke, das hat den Trick getan. Schade, dass diese Funktionalität nicht über eine GUI zugänglich ist.
Hassan Syed
@rfusca Du wirst im Grunde alles doppelt laufen lassen, wo ist der Beweis dafür? Bei einigen Experimenten habe ich dieses Verhalten nicht gezeigt.
Sebastian Dressler
Beachten Sie, dass hier auf eine 7 Jahre alte Datenbank verwiesen wird. Es funktioniert dann wahrscheinlich nicht mehr so, wenn Sie nicht die gleichen Ergebnisse sehen.
Rfusca
16

Zusätzlich zu @ rfuscas Rat: SQL-Anweisungen in plpgsql-Funktionen werden als verschachtelte Anweisungen betrachtet und Sie müssen den zusätzlichen Parameter festlegen auto_explain.log_nested_statements.

Im Gegensatz zu einigen anderen Erweiterungen, Sie nicht laufen müssen CREATE EXTENSIONfür diese ein. Laden Sie es einfach dynamisch in Ihre Sitzung mit LOAD. Ihre Sitzung könnte folgendermaßen aussehen:

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

Kann eine Menge Protokollausgaben erzeugen.
Das aktuelle Handbuch zu auto_explain.
Depesz hat einen Blog-Artikel darüber geschrieben, als er mit PostgreSQL 8.4 eingeführt wurde.

Erwin Brandstetter
quelle
+1 - so lange her, ich habe vergessen, die Zeile
log_nested_statements
3
Sie haben es verdient, das richtige Tool zu finden.
Erwin Brandstetter
Ich besitze eine Postgres-Datenbank für den Managed Service (RDS) von Amazon, für den LOAD 'auto_explain';Retouren erfolgen ERROR: access to library "auto_explain" is not allowed. Was in diesem Fall? Ich hatte einige Erfolge beim Hacken meiner Funktionen, return query explain select …aber das ist mühsam und langsam.
Vornehmste