plpgsql로 작성된 함수 호출의 Postgres 쿼리 계획


19

를 사용하는 경우 그것은 가능 pgadmin또는 plsql돌며 실행되는 SQL 문에 대한 쿼리 계획의 보류를 얻을 U 버리는 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

자동 설명 을 사용할 수 있어야합니다 . 전원을 켜고

SET auto_explain.log_min_duration = 0;

해당 세션에서 실행되는 모든 명령문에 대한 계획을 로그에 가져와야합니다.

당신은 또한 설정하려면

SET auto_explain.log_analyze = true; 그러나 '실제'로 한 번, 분석을 설명하기 위해 한 번만 모든 것을 두 번 실행합니다. 비 타이밍 성능 테스트 단계에서이 결과는 실제로 발생한 계획을 제공하므로 EXPLAIN 계획보다 훨씬 유용 할 수 있습니다.


4
@Erwin이 아래에서 지적한 것처럼 auto_explain.log_nested_statements = ON도 설정해야합니다.
rfusca

고마워, 그 트릭을했다. GUI를 통해이 기능에 액세스 할 수없는 것은 부끄러운 일입니다.
Hassan Syed

@rfusca 당신은 본질적으로 모든 것을 두 배로 실행할 것 입니다. 일부 실험에서는이 동작을 보여주지 않았습니다.
Sebastian Dressler

이 시점에서 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에서 소개되었을 때 블로그 기사를 작성했습니다 .


하나는 - 너무 오래되어, 나는 log_nested_statements 라인을 설정할 필요 잊어
rfusca을

3
당신은 어쨌든 올바른 도구를 기르는 것에 대한 가치가 있습니다.
Erwin Brandstetter

아마존의 관리 서비스 (RDS)에 postgres 데이터베이스가 있는데,에 대해 LOAD 'auto_explain';반환합니다 ERROR: access to library "auto_explain" is not allowed. 이 경우에는 무엇입니까? 나는 내 기능을 해킹하는 데 성공 return query explain select …했지만 힘들고 느립니다.
poshest
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.