Piano di query Postgres di una chiamata di funzione scritta in plpgsql


19

E 'possibile quando si utilizza il pgadmino plsqlper ottenere una sospensione di un piano di query per un'istruzione SQL eseguita all'interno di un u ser d efined f unzione (UDF) utilizzando EXPLAIN. Quindi, come posso ottenere il piano di query per una particolare chiamata di un UDF? Vedo l'UDF sottratto in un'unica operazione F()in pgadmin.

Ho esaminato la documentazione ma non sono riuscito a trovare nulla.

Attualmente sto estraendo le dichiarazioni e le eseguo manualmente. Ma questo non lo taglierà per query di grandi dimensioni.

Ad esempio, considera l'UDF di seguito. Questo UDF, anche se ha la capacità di stampare la sua stringa di query, non funzionerà con un copia-incolla poiché ha una tabella temporanea creata localmente, che non esiste quando la incolli e la esegui.

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;

Risposte:


16

Dovresti essere in grado di utilizzare la spiegazione automatica . Accendilo e

SET auto_explain.log_min_duration = 0;

e dovresti ottenere i piani nel tuo registro per tutte le istruzioni eseguite in quella sessione.

Si potrebbe anche voler set

SET auto_explain.log_analyze = true; ma essenzialmente eseguirai tutto doppio - una volta per "reale" e una volta per SPIEGARE ANALISI. Durante una fase di test delle prestazioni senza tempistica, questo output può essere molto più utile dei soli piani EXPLAIN, in quanto fornisce quale piano è effettivamente accaduto.


4
Come @Erwin sottolinea di seguito, è necessario impostare anche auto_explain.log_nested_statements = ON.
rfusca,

Grazie, ha fatto il trucco. è un peccato che questa funzionalità non sia accessibile tramite una GUI.
Hassan Syed,

@rfusca essenzialmente farai tutto il doppio dov'è la prova per questo? Alcuni esperimenti che ho fatto non mostrano questo comportamento.
Sebastian Dressler,

Realizza che questo fa riferimento a un database di 7 anni a questo punto. Probabilmente non funziona più così se non vedi gli stessi risultati.
rfusca,

16

I oltre al consiglio di @ rfusca: le istruzioni SQL all'interno delle funzioni di plpgsql sono considerate istruzioni nidificate ed è necessario impostare il parametro aggiuntivo auto_explain.log_nested_statements.

A differenza di altre estensioni, non devi correre CREATE EXTENSIONper questo. Basta caricarlo dinamicamente nella sessione con LOAD. La tua sessione potrebbe apparire così:

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

Può produrre un sacco di output del log.
Il manuale attuale su auto_explain.
Depesz ha scritto un articolo sul blog quando è stato introdotto con PostgreSQL 8.4.


+1 - è passato così tanto tempo che mi sono dimenticato di dover impostare la riga
log_nested_statements

3
Ti meriti comunque il merito di aver tirato fuori lo strumento giusto.
Erwin Brandstetter,

Ho un database Postgres sul servizio gestito di Amazon (RDS), per il quale LOAD 'auto_explain';ritorna ERROR: access to library "auto_explain" is not allowed. Cosa in quel caso? Ho avuto un certo successo con l'hacking delle mie funzioni return query explain select …ma è laborioso e lento.
poshest
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.