Kế hoạch truy vấn Postgres của một lời gọi hàm được viết bằng plpgsql


19

Có thể khi sử dụng pgadminhoặc plsqlđể có được một tổ chức của một kế hoạch truy vấn cho một tuyên bố sql thực hiện bên trong một u ser d efined f bôi (UDF) sử dụng EXPLAIN. Vậy làm thế nào để tôi có được kế hoạch truy vấn cho một yêu cầu cụ thể của UDF? Tôi thấy UDF được trừu tượng hóa thành một hoạt động F()trong pgadmin.

Tôi đã xem tài liệu nhưng tôi không thể tìm thấy bất cứ điều gì.

Hiện tại tôi đang rút các báo cáo và chạy chúng bằng tay. Nhưng điều này sẽ không cắt nó cho các truy vấn lớn.

Ví dụ, hãy xem xét UDF dưới đây. UDF này, mặc dù nó có khả năng in ra chuỗi truy vấn của nó, sẽ không hoạt động với bản sao chép vì nó có một bảng tạm thời được tạo cục bộ, không tồn tại khi bạn dán và thực thi nó.

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;

Câu trả lời:


16

Bạn sẽ có thể sử dụng tự động giải thích . Bật nó lên và

SET auto_explain.log_min_duration = 0;

và bạn sẽ nhận được các kế hoạch trong nhật ký của mình cho tất cả các câu lệnh chạy trong phiên đó.

Bạn cũng có thể muốn đặt

SET auto_explain.log_analyze = true; nhưng về cơ bản, bạn sẽ chạy mọi thứ gấp đôi - một lần cho 'thực tế' và một lần để GIẢI THÍCH PHÂN TÍCH trên. Trong giai đoạn thử nghiệm hiệu năng không đúng thời gian, đầu ra này có thể hữu ích hơn nhiều so với các kế hoạch EXPLAIN, vì nó cung cấp kế hoạch thực sự đã xảy ra.


4
Như @Erwin chỉ ra bên dưới, bạn cũng nên đặt auto_explain.log_nested_statements = ON.
rfusca

Cảm ơn, điều đó đã lừa thật xấu hổ khi chức năng này không thể truy cập thông qua GUI.
Hassan Syed

@rfusca về cơ bản bạn sẽ chạy mọi thứ gấp đôi đâu là bằng chứng cho điều đó? Một số thí nghiệm tôi đã không thể hiện hành vi này.
Sebastian Dressler

Nhận ra điều này đang tham khảo một cơ sở dữ liệu 7 năm tuổi tại thời điểm này. Nó có thể không hoạt động như vậy nữa nếu bạn không thấy kết quả tương tự.
rfusca

16

Tôi thêm vào lời khuyên của @ rfusca: Các câu lệnh SQL bên trong các hàm plpgsql được coi là các câu lệnh lồng nhau và bạn cần đặt Tham số bổ sung auto_explain.log_nested_statements.

Không giống như một số tiện ích mở rộng khác, bạn không phải chạy CREATE EXTENSIONcho tiện ích mở rộng này. Chỉ cần tải nó động vào phiên của bạn với LOAD. Phiên của bạn có thể trông như thế này:

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

Có thể sản xuất rất nhiều đầu ra log.
Các hiện thủ công trên auto_explain.
Depesz đã viết một bài viết trên blog về nó khi nó được giới thiệu với PostgreQuery 8.4.


+1 - đã quá lâu, tôi quên mất việc cần thiết lập dòng
log_nested_statements

3
Bạn xứng đáng được tín nhiệm vì đã đưa ra công cụ phù hợp nào.
Erwin Brandstetter

Tôi có một cơ sở dữ liệu postgres trên dịch vụ được quản lý của Amazon (RDS) để LOAD 'auto_explain';trả về ERROR: access to library "auto_explain" is not allowed. Điều gì trong trường hợp đó? Tôi đã thành công trong việc hack các chức năng của mình return query explain select …nhưng điều đó rất tốn công và chậm chạp.
chắc chắn nhất
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.