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


19

使用するとき、それは可能ですpgadminplsql内部で実行されるSQL文のクエリプランのホールドを取得するために、U SER D efined F慰め(UDF)を使用しますEXPLAIN。それでは、UDFの特定の呼び出しに対するクエリプランを取得するにはどうすればよいですか?F()pgadminでUDFが抽象化されて単一の操作になっています。

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

現在、ステートメントを引き出して手動で実行しています。しかし、これは大規模なクエリに対しては削減されません。

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

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

SET auto_explain.log_min_duration = 0;

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

設定することできます

SET auto_explain.log_analyze = true; しかし、基本的にすべてを二重に実行します-1回は「本物」で、もう1回はEXPLAIN ANALYZEを実行します。タイミング以外のパフォーマンステストフェーズでは、この出力はEXPLAINプランのみよりもはるかに役立ちます。これは、実際に起こったプランを提供するためです。


4
@Erwinが以下で指摘しているように、auto_explain.log_nested_statements = ONも設定する必要があります。
-rfusca

おかげで、それでうまくいきました。GUIを介してこの機能にアクセスできないのは残念です。
ハッサンSyed

@rfusca あなたは本質的にすべてを二重実行するでしょう、その証拠はどこですか?私がやったいくつかの実験では、この動作を示していません。
セバスチャン・ドレスラー

この時点で7年前のデータベースを参照していることを理解してください。同じ結果が表示されない場合は、おそらくそのようには動作しません。
rfusca

16

@rfuscaのアドバイスに加えて、plpgsql関数内のSQLステートメントはネストされたステートメントと見なされるため、追加のParameterを設定する必要があります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ラインを設定する必要が忘れてしまった
rfusca

3
いずれにせよ、適切なツールを開発したことは評価に値します。
アーウィンブランドステッター

Amazonのマネージドサービス(RDS)にpostgresデータベースがありLOAD 'auto_explain';ますERROR: access to library "auto_explain" is not allowed。その場合はどうですか?私は自分の機能をハッキングすることでいくらか成功しましたreturn query explain select …が、それは面倒で遅いです。
豪華な
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.