如何摆脱游标循环以提高性能?

时间:2013-03-20 19:54:51

标签: oracle plsql oracle10g oracle11g

我有一个函数如下,由于游标循环,性能非常差。我需要有人帮我摆脱光标并使用一个语句代替。任何人都可以提供帮助,非常感谢!!

function get_pat_liv_donor_trans_date(p_patr_id IN NUMBER) return date is
  v_transplant_date date;
  v_rst             date;
  v_patr_id         number;

  --get patient all the patr_id(s) which has been transplanted (kidney) with living donor
  cursor c_cur1 is
    select distinct patr.patr_id
      from pat,
           pat_register         patr,
           pat_register_org_det prod,
           transplant_org_det   tod,
           transplant           trans,
           don,
           don_org_con          doc,
           allo,
           all_pat_list         apl,
           ORG_SPEC             OS,
           DON_ORG_OFF_RES      DOOR
     where pat.pat_id = patr.pat_id
       and patr.patr_id = prod.patr_id
       and prod.prod_id = tod.prod_id --patient has been transplanted (kidney)
       and tod.orgsp_id in (5, 6, 7, 8, 9) --5:Kidney-Unknown, 6:Kidney-Right, 7:Kidney-Left, 8:Kidney-Both, 9:Kidney-Single
       and trans.patr_id = patr.patr_id
       and don.don_id = doc.don_id
       and doc.doc_id = allo.doc_id
       and allo.all_id = apl.all_id
       and apl.prod_id = prod.prod_id
       and don.cadaveric_flg = 'N' --living donor
       and OS.ORGSP_ID = DOOR.ORGSP_ID
       AND DOOR.ACCEPT_IND = 'Y'
       AND DOOR.ACCEPT_CANCEL_DATE IS NULL
       AND APL.APL_ID = DOOR.APL_ID
       and pat.pat_id in (select pat.pat_id
                            from pat, pat_register patr
                           where patr.patr_id = p_patr_id)
       and patr.patr_id not in -- Not suspend registration
           (select patr_id from pat_register_suspend where end_date is null)
          --Not canceled registration
       and patr.exp_date is null;

  --get patient transplant_date which has been transplanted (kidney) with living
  cursor c_cur2 is
    select min(distinct trans.transplant_date)
      from pat,
           pat_register         patr,
           pat_register_org_det prod,
           transplant_org_det   tod,
           transplant           trans,
           don,
           don_org_con          doc,
           allo,
           all_pat_list         apl,
           ORG_SPEC             OS,
           DON_ORG_OFF_RES      DOOR
     where pat.pat_id = patr.pat_id
       and patr.patr_id = prod.patr_id
       and prod.prod_id = tod.prod_id --patient has been transplanted (kidney)
       and tod.orgsp_id in (5, 6, 7, 8, 9) --5:Kidney-Unknown, 6:Kidney-Right, 7:Kidney-Left, 8:Kidney-Both, 9:Kidney-Single
       and trans.patr_id = patr.patr_id
       and don.don_id = doc.don_id
       and doc.doc_id = allo.doc_id
       and allo.all_id = apl.all_id
       and apl.prod_id = prod.prod_id
       and patr.patr_id = v_patr_id
       and don.cadaveric_flg = 'N' --living donor
       and OS.ORGSP_ID = DOOR.ORGSP_ID
       AND DOOR.ACCEPT_IND = 'Y'
       AND DOOR.ACCEPT_CANCEL_DATE IS NULL
       AND APL.APL_ID = DOOR.APL_ID;

begin
  --if patient current is Not waiting for pancreas
  if (tttt_kp_allocation.is_pat_waiting_for_pancreas(p_patr_id) != 'Y') then
    return v_rst;
  end if;

  open c_cur1;
  loop
    fetch c_cur1
      into v_patr_id;
    exit when c_cur1%notfound;

    open c_cur2;
    fetch c_cur2
      into v_transplant_date;

    if (v_rst is null) and (v_transplant_date is not null) then
      v_rst := v_transplant_date;
    end if;

    --get earlier of Date of Living Donor transplant for PAK
    if (v_rst is not null) and (v_transplant_date is not null) then
      if (v_rst - v_transplant_date > 0) then
        v_rst := v_transplant_date;
      end if;
    end if;

    close c_cur2;

  end loop;
  close c_cur1;

  return v_rst;
end;

c_cur1将返回如下:

patr_id
1001
1002
1003
1004

c_cur2将返回如下日期:

2001-jan-01   ( patr_id : 1001)
2002-jan-01   ( patr_id : 1002)
2003-jan-01   ( patr_id : 1003)
2004-jan-01   ( patr_id : 1004)

最终结果v_rst将从(2001-jan-01,2002-jan-01,2003-jan-01,2004-jan-01)获得最短日期

所以,我需要一种方法来摆脱游标循环(性能太差)并使用一个语句获得最终结果。

2 个答案:

答案 0 :(得分:0)

以下内容可能会对您有所帮助。


function get_pat_liv_donor_trans_date(p_patr_id IN NUMBER) return date is
  v_transplant_date date;
  v_rst             date;
  v_patr_id         number;
--get patient all the patr_id(s) which has been transplanted (kidney) with living donor
select case when v_rst is null and B.transplant_date is not null then v_rst := v_transplant_date
            when v_rst IS NOT NULL AND B.transplant_date is not null AND v_rst - v_transplant_date > 0 THEN v_rst := v_transplant_date
       END
from (
    select distinct patr.patr_id
      from pat,
           pat_register         patr,
           pat_register_org_det prod,
           transplant_org_det   tod,
           transplant           trans,
           don,
           don_org_con          doc,
           allo,
           all_pat_list         apl,
           ORG_SPEC             OS,
           DON_ORG_OFF_RES      DOOR
     where pat.pat_id = patr.pat_id
       and patr.patr_id = prod.patr_id
       and prod.prod_id = tod.prod_id --patient has been transplanted (kidney)
       and tod.orgsp_id in (5, 6, 7, 8, 9) --5:Kidney-Unknown, 6:Kidney-Right, 7:Kidney-Left, 8:Kidney-Both, 9:Kidney-Single
       and trans.patr_id = patr.patr_id
       and don.don_id = doc.don_id
       and doc.doc_id = allo.doc_id
       and allo.all_id = apl.all_id
       and apl.prod_id = prod.prod_id
       and don.cadaveric_flg = 'N' --living donor
       and OS.ORGSP_ID = DOOR.ORGSP_ID
       AND DOOR.ACCEPT_IND = 'Y'
       AND DOOR.ACCEPT_CANCEL_DATE IS NULL
       AND APL.APL_ID = DOOR.APL_ID
       and pat.pat_id in (select pat.pat_id
                            from pat, pat_register patr
                           where patr.patr_id = p_patr_id)
       and patr.patr_id not in -- Not suspend registration
           (select patr_id from pat_register_suspend where end_date is null)
          --Not canceled registration
       and patr.exp_date is null
    ) A 
    inner join ( 
    select patr.patr_id, min(trans.transplant_date)
      from pat,
           pat_register         patr,
           pat_register_org_det prod,
           transplant_org_det   tod,
           transplant           trans,
           don,
           don_org_con          doc,
           allo,
           all_pat_list         apl,
           ORG_SPEC             OS,
           DON_ORG_OFF_RES      DOOR
     where pat.pat_id = patr.pat_id
       and patr.patr_id = prod.patr_id
       and prod.prod_id = tod.prod_id --patient has been transplanted (kidney)
       and tod.orgsp_id in (5, 6, 7, 8, 9) --5:Kidney-Unknown, 6:Kidney-Right, 7:Kidney-Left, 8:Kidney-Both, 9:Kidney-Single
       and trans.patr_id = patr.patr_id
       and don.don_id = doc.don_id
       and doc.doc_id = allo.doc_id
       and allo.all_id = apl.all_id
       and apl.prod_id = prod.prod_id
       and patr.patr_id = v_patr_id
       and don.cadaveric_flg = 'N' --living donor
       and OS.ORGSP_ID = DOOR.ORGSP_ID
       AND DOOR.ACCEPT_IND = 'Y'
       AND DOOR.ACCEPT_CANCEL_DATE IS NULL
       AND APL.APL_ID = DOOR.APL_ID
     group by patr.patr_id
     ) B
     on A.patr_id = B.patr_id
  return v_rst;

答案 1 :(得分:0)

您对c_cur1的查询似乎不正确。其结果不依赖于p_patr_id参数 提到p_patr_id的唯一位置是以下子查询:

(select pat.pat_id
 from pat, pat_register patr
 where patr.patr_id = p_patr_id)

此子查询的结果显然不依赖于p_patr_id。 : - )