4

I have a really basic plpgsql stored procedure like this:

create or replace procedure new_emp_sp (f_name varchar, l_name varchar, age integer, threshold integer)
language plpgsql
as $$
declare
    new_emp_count integer;
begin
    INSERT INTO employees (id, first_name, last_name, age)
        VALUES (nextval('emp_id_seq'), 
                random_string(10),
                random_string(20),
                age);
    select count(*) into new_emp_count from employees where age > threshold;
    update dept_employees set emp_count = new_emp_count where id = 'finance';
end; $$

After calling this stored procedure using call, how do I get the query plans for each of the statements that were executed by the procedure?

Found a couple of StackOverflow answers for a similar requirement but with functions instead of procedures using the auto_explain module and I followed the below steps but it did not work:

  1. Executed LOAD '$libdir/plugins/auto_explain'; (I am using an AWS RDS PostgreSQL instance and found this command in this documentation)

  2. Executed SET auto_explain.log_min_duration = 0;

  3. Executed SET auto_explain.log_analyze = true;

  4. Executed SET auto_explain.log_nested_statements = true;

But after executing the procedure, I did not see any visible changes in the output.

For my current requirement I cannot access any log files on the database server and can only run commands on the server through a client / programmatically

marc_s
  • 732,580
  • 175
  • 1,330
  • 1,459
user9492428
  • 603
  • 1
  • 9
  • 25

2 Answers2

3

you can have log messages sent to the client:

set client_min_messages TO log;

This works fine with auto_explain.log_nested_statements (in psql, anyway). I use it all the time to avoid needing to go scrounge through the log file.

jjanes
  • 37,812
  • 5
  • 27
  • 34
1

Is this the only way of getting the query plan for a stored procedure/function?

There is another way without installing auto_explain. The EXPLAIN command basically returns a set of text, and you can work with that in a PL/pgSQL code block:

CREATE OR REPLACE PROCEDURE pg_temp.get_plan ()
  LANGUAGE plpgsql AS
$proc$
DECLARE
   _line text;
BEGIN
   FOR _line IN
      EXPLAIN ANALYZE
      SELECT 1            -- your query here !!!
   LOOP
      RAISE NOTICE '%', _line;
   END LOOP;
END
$proc$;

CALL pg_temp.get_plan();

You'll get in your client (any client that shows notices):

NOTICE:  Result  (cost=0.00..0.01 rows=1 width=4) (actual time=0.004..0.005 rows=1 loops=1)
NOTICE:  Planning Time: 0.045 ms
NOTICE:  Execution Time: 0.035 ms
CALL

See:

Erwin Brandstetter
  • 605,456
  • 145
  • 1,078
  • 1,228
  • Thanks for the answer. It does work only issue for me with your approach is that a new procedure will need to be created and that does not fit my current use case. No issue other than that basically. Hope it will help someone else. Thanks again! – user9492428 Mar 07 '22 at 17:42