Plpgsql ile yazılmış bir işlev çağrısının postgres sorgu planı


19

Kullanırken Mümkün pgadminveya plsqlbir iç infaz eden sql deyimi için bir sorgu planı da ele geçirmeleri u ser d efined f İşlev (UDF) kullanarak EXPLAIN. Peki, bir UDF'nin belirli bir çağrılması için sorgu planını nasıl elde edebilirim? UDF'nin F()pgadmin'de tek bir operasyona ayrıldığını görüyorum.

Belgelere baktım ama hiçbir şey bulamadım.

Şu anda ifadeleri çıkarıyorum ve manuel olarak çalıştırıyorum. Ama bu büyük sorgular için kesmeyecek.

Örneğin, aşağıdaki UDF'yi düşünün. Bu UDF, sorgu dizesini yazdırma yeteneğine sahip olsa da, yapıştırdığınızda ve yürüttüğünüzde mevcut olmayan yerel olarak oluşturulan geçici bir tabloya sahip olduğu için bir kopyala yapıştır ile çalışmaz.

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;

Yanıtlar:


16

Otomatik açıklamayı kullanabilmeniz gerekir . Açın ve

SET auto_explain.log_min_duration = 0;

ve o oturumda çalıştırılan tüm ifadelerin planlarını günlüğünüze almalısınız.

Sen belki de sette istiyorum

SET auto_explain.log_analyze = true; ancak temelde her şeyi iki kez çalıştırırsınız - bir kez 'gerçek' ve bir kez ANALİZİ KEŞFEDİN. Zamanlama dışı bir performans testi aşamasında, bu çıktı gerçekte ne olduğunu sağladığı için sadece EXPLAIN planlarından çok daha yararlı olabilir.


4
@Erwin'in aşağıda belirttiği gibi, auto_explain.log_nested_statements = ON değerini de ayarlamanız gerekir.
rfusca

Teşekkürler, bu hile yaptı. bu işlevselliğe bir GUI aracılığıyla erişilememesi utanç verici.
Hassan Syed

@rfusca temelde her şeyi iki katına çıkarırsınız bunun kanıtı nerede? Yaptığım bazı deneyler bu davranışı göstermedi.
Sebastian Dressler

Bunun bu noktada 7 yaşındaki bir veritabanına atıfta bulunduğunu anlayın. Aynı sonuçları görmüyorsanız, artık böyle çalışmaz.
rfusca

16

@ Rfusca'nın tavsiyesine ek olarak: plpgsql işlevleri içindeki SQL deyimleri iç içe deyimler olarak kabul edilir ve ek Parametre ayarlamanız gerekir auto_explain.log_nested_statements.

Diğer bazı uzantılardan farklı olarak, bunun için çalıştırmanız gerekmezCREATE EXTENSION . Sadece oturumunuzla dinamik olarak yükleyin LOAD. Sizin oturumu aşağıdaki gibi görünebilir:

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

Çok sayıda günlük çıktısı üretebilir . Geçerli auto_explain manuel. Depesz , PostgreSQL 8.4 ile tanıtıldığında bu konuda bir blog makalesi yazdı .


+1 - çok uzun zamandır, log_nested_statements satırını ayarlamayı unuttum
rfusca

3
Yine de doğru aracı getirdiğiniz için krediyi hak ediyorsunuz.
Erwin Brandstetter

Ben Amazon'un yönetilen hizmet (RDS), için bir postgres veritabanı LOAD 'auto_explain';döner ERROR: access to library "auto_explain" is not allowed. Bu durumda ne var? İşlevlerimi hacklemede bazı başarılar yaşadım, return query explain select …ancak bu zahmetli ve yavaş.
poshest
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.