I wrote a stored procedure in Postgres which takes two integer parameters as input.
CREATE OR REPLACE FUNCTION public.tickets_long_open(comp_id integer, days integer, ref refcursor) RETURNS refcursor AS $$ begin open ref for select q.svc_ord_nbr, q.po_nbr, q.state, q.city, q.cust_name, q.days_open, q.status from (select a.svc_ord_nbr, a.po_nbr, a.create_dtm, b.sap_sls_org_name, b.cust_lvl_2_name, d.close_dtm, d.debit_memo_dtm, l.state, l.city, l.cust_name, date_part('day', (select case when d.close_dtm is null then now() else d.close_dtm end close_ts) - a.create_dtm) as days_open, case when d.close_dtm is null and d.debit_memo_dtm is null then 'OPEN' else 'CLOSED' end status from dmt_mas_svc_ord_fact a inner join dmt_mas_cust_dim b on a.shipto_cust_id = b.cust_id inner join dmt_mas_svc_ord_degen_dim d on a.svc_ord_id = d.svc_ord_id inner join store_location l on b.cust_name = l.cust_name where b.sap_sls_org_name like '%US%' and a.create_dtm >= now() - interval '12 months' and l.company_id = comp_id) q where q.days_open > days order by q.state, q.city, q.cust_name; return ref; end; $$ language plpgsql; In order to display the result set, I include cursor as the third parameter so I can run the following to fetch the cursor:
begin; select tickets_long_open(1, 30, 'refc'); fetch all in "refc"; It took 26 minutes to return 88 rows of records.
If I remove the first two parameters comp_id and days and hard code them in query. The fetch only takes 19 seconds for select tickets_long_open('refc'). Everything else is the same.
Why does it take this long to fetch the result set when I have the two parameters? And why removing the parameters suddenly made it so much quicker?
EDIT: After some debugging, it turns out the query is only slow only when it takes input variables at run time. Returning it as table does not change anything. Changing function to plain sql does not help either
CREATE OR REPLACE FUNCTION public.tickets_long_open(comp_id integer, days double precision) RETURNS TABLE(svc_ord_nbr text, po_nbr text, state text, city text, cust_name text, days_open double precision, status text) AS $$ select q.svc_ord_nbr, q.po_nbr, q.state, q.city, q.cust_name, q.days_open, q.status from (select a.svc_ord_nbr, a.po_nbr, a.create_dtm, b.sap_sls_org_name, b.cust_lvl_2_name, d.close_dtm, d.debit_memo_dtm, l.state, l.city, l.cust_name, date_part('day', (select case when d.close_dtm is null then now() else d.close_dtm end close_ts) - a.create_dtm) as days_open, case when d.close_dtm is null and d.debit_memo_dtm is null then 'OPEN' else 'CLOSED' end status from dmt_mas_svc_ord_fact a inner join dmt_mas_cust_dim b on a.shipto_cust_id = b.cust_id inner join dmt_mas_svc_ord_degen_dim d on a.svc_ord_id = d.svc_ord_id inner join store_location l on b.cust_name = l.cust_name where b.sap_sls_org_name like '%US%' and a.create_dtm >= now() - interval '12 months' and l.company_id = comp_id) q where q.days_open > days order by q.state, q.city, q.cust_name; end; $$ language sql stable;
EXPLAIN ANALYZEand some information about table size, index, current time performance, desire time, etc.Slowis a relative term and we need a real value to compare.