web-dev-qa-db-ja.com

plpgsqlで記述された関数呼び出しのPostgresクエリプラン

pgadminまたはplsqlを使用すると、 ser d内で実行されるSQLステートメントのクエリプランを取得できます。 efined f unction(UDF)using EXPLAIN。では、UDFの特定の呼び出しのクエリプランを取得するにはどうすればよいですか? UDFはpgadminの単一の操作F()に抽象化されています。

ドキュメントを確認しましたが、何も見つかりませんでした。

現在、私はステートメントを引き出して手動で実行しています。しかし、これは大きなクエリの場合はそれを削減するつもりはありません。

たとえば、以下の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;
19
Hassan Syed

auto-explain を使用できるはずです。オンにして

SET auto_explain.log_min_duration = 0;

そして、そのセッションで実行されるすべてのステートメントの計画をログに取得する必要があります。

あなたmightも設定したい

SET auto_explain.log_analyze = true;ただし、基本的にはすべてを2倍に実行します。1回は「実際の」、もう1回はEXPLAIN ANALYZEを実行します。タイミング以外のパフォーマンステストフェーズでは、この出力はEXPLAIN計画だけよりもはるかに有用です。これは、実際に発生した計画を提供するためです。

16
rfusca

@rfuscaのアドバイスに加えて、plpgsql関数内のSQLステートメントはネストされたステートメントと見なされ、追加のパラメーター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のcurrentマニュアル
Depeszは、PostgreSQL 8.4で導入されたときに それに関するブログ記事 を書きました。

16