为什么用postgres函数查询输入变量需要这么长时间

时间:2017-10-30 20:47:52

标签: postgresql cursor plpgsql

我在Postgres中编写了一个存储过程,它接受两个整数参数作为输入。

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;

为了显示结果集,我将cursor作为第三个参数包含在内,这样我就可以运行以下内容来获取光标:

begin;
select tickets_long_open(1, 30, 'refc');
fetch all in "refc";

返回88行记录需要26分钟。

如果我删除前两个参数comp_iddays并在查询中对其进行硬编码。 select tickets_long_open('refc')的抓取只需19秒。其他一切都是一样的。

为什么在我有两个参数时需要很长时间来获取结果集?为什么删除参数会突然变得更快?

修改: 在一些调试之后,事实证明只有在运行时获取输入变量时查询才会变慢。将它作为表返回不会改变任何东西。将函数更改为普通sql无济于事

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;

0 个答案:

没有答案