Rencana kueri postgres dari pemanggilan fungsi ditulis dalam plpgsql

19

Ini mungkin ketika menggunakan pgadminatau plsqluntuk mendapatkan suatu pegangan dari rencana permintaan untuk pernyataan sql dieksekusi di dalam u ser d efined f pengurapan (UDF) menggunakan EXPLAIN. Jadi, bagaimana saya bisa mengetahui rencana kueri untuk permintaan khusus UDF? Saya melihat UDF diabstraksi menjadi satu operasi F()di pgadmin.

Saya telah melihat dokumentasi tetapi saya tidak dapat menemukan apa pun.

Saat ini saya mengeluarkan pernyataan dan menjalankannya secara manual. Tapi ini tidak akan memotongnya untuk permintaan besar.

Misalnya, perhatikan UDF di bawah ini. UDF ini, meskipun memiliki kemampuan untuk mencetak string kueri, tidak akan berfungsi dengan salin-tempel karena memiliki tabel sementara yang dibuat secara lokal, yang tidak ada saat Anda menempelkan dan menjalankannya.

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
sumber

Jawaban:

16

Anda harus dapat menggunakan penjelasan otomatis . Nyalakan dan

SET auto_explain.log_min_duration = 0;

dan Anda harus mendapatkan rencana di log Anda untuk semua pernyataan dijalankan di sesi itu.

Anda mungkin juga ingin mengatur

SET auto_explain.log_analyze = true; tetapi pada dasarnya Anda akan menjalankan semuanya dobel - sekali untuk 'nyata' dan sekali untuk MENJELASKAN ANALISIS. Selama fase pengujian kinerja non-waktu, output ini dapat jauh lebih berguna daripada rencana EXPLAIN saja, karena memberikan rencana apa yang sebenarnya terjadi.

rfusca
sumber
4
Seperti yang ditunjukkan @Erwin di bawah ini, Anda harus mengatur auto_explain.log_nested_statements = ON juga.
rfusca
Terima kasih, itu berhasil. Sayang sekali fungsi ini tidak dapat diakses melalui GUI.
Hassan Syed
@ rfusca pada dasarnya Anda akan menjalankan semuanya berlipat ganda di mana buktinya? Beberapa percobaan yang saya lakukan tidak menunjukkan perilaku ini.
Sebastian Dressler
Sadarilah ini mereferensikan basis data berusia 7 tahun pada saat ini. Kemungkinan tidak lagi berfungsi seperti itu jika Anda tidak melihat hasil yang sama.
rfusca
16

Saya menambahkan saran @ rfusca: Pernyataan SQL di dalam fungsi plpgsql dianggap sebagai pernyataan bersarang dan Anda perlu mengatur Parameter tambahan auto_explain.log_nested_statements.

Tidak seperti beberapa ekstensi lain, Anda tidak harus menjalankan yang CREATE EXTENSIONini. Cukup masukkan secara dinamis ke dalam sesi Anda dengan LOAD. Sesi Anda dapat terlihat seperti ini:

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

Dapat menghasilkan banyak output log.
The arus manual pada auto_explain.
Depesz menulis artikel blog tentang hal itu ketika diperkenalkan dengan PostgreSQL 8.4.

Erwin Brandstetter
sumber
+1 - sudah sangat lama, saya lupa perlu mengatur baris
log_nested_statements
3
Anda pantas mendapatkan kredit karena memunculkan alat yang tepat.
Erwin Brandstetter
Saya memiliki database postgres pada layanan terkelola Amazon (RDS), yang LOAD 'auto_explain';hasilnya dikembalikan ERROR: access to library "auto_explain" is not allowed. Dalam hal apa? Saya sudah cukup berhasil meretas fungsi saya return query explain select …tetapi itu melelahkan dan lambat.
poshest