优化一个简单的程序

时间:2017-05-04 08:46:49

标签: oracle stored-procedures plsql

下面是我的程序,执行需要51秒,我想只在找到一个计数时返回游标,以防其他任何东西将返回消息和游标为null。如果找到游标消息为null ..

我首先通过查询进行计数并稍后通过相同的查询填充数据,但仅在count为1的情况下。

无论如何都可以在时间上优化它。?

create or replace PROCEDURE sp_cp_getcrnnofrmmobdob(P_MobileNo    IN VARCHAR2,
                                                    P_Dob         IN VARCHAR2,
                                                    p_Output      out SYS_REFCURSOR,
                                                    p_Message     OUT VARCHAR2) IS

  vCRN      Varchar2(50) := '';
  vCustid   varchar2(50) := '';
  vMobno    varchar2(50) := '';
  vCustname varchar2(400) := '';
  vCustDob  varchar2(50) := '';
  vcount    int := 0;

BEGIN
  p_Message := '';

  OPEN p_Output FOR
    select 1 from dual;

  Select count(*)
    into vcount
    FROM (select distinct(C.fw_customer_id_c) crn,
                C.Cust_Id_n custid,
                c.customername custname,
                c.dob custdob,
                A.MOBILE mobileno
                from      FCH_CASTRANSACTION.NBFC_CUSTOMER_M C,
                                                FCH_CASMASTER.nbfc_address_m A
                where   A.BPID = C.Cust_Id_n and
                                                A.mobile = P_MobileNo and
                                                TO_CHAR(TO_DATE(C.DOB, 'DD-MON-YY'),'DD-MON-YY')=TO_CHAR(TO_DATE(P_Dob,'DD/MM/YYYY'),'DD-MON-YY'));

  if (vcount = 1) then

    select B.crn,
           B.custid,
           B.mobileno,
           B.custname,
           B.custdob
      into vCRN, vCustid, vMobno, vCustname, vCustDob
      from (select distinct(C.fw_customer_id_c) crn,
                                                C.Cust_Id_n custid,
                                                c.customername custname,
                                                c.dob custdob,
                                                A.MOBILE mobileno
                                                from      FCH_CASTRANSACTION.NBFC_CUSTOMER_M C,
                                                          FCH_CASMASTER.nbfc_address_m A
                                                where   A.BPID = C.Cust_Id_n and
                                                        A.mobile = P_MobileNo and
                                                        TO_CHAR(TO_DATE(C.DOB, 'DD-MON-YY'),'DD-MON-YY')=TO_CHAR(TO_DATE(P_Dob,'DD/MM/YYYY'),'DD-MON-YY')) B;

    if ((vCRN = '') OR (vCRN IS Null)) then
      p_Message := 'No data found for entered details';

    else
      if ((vMobno <> P_MobileNo) OR (vMobno IS Null)) then
        p_Message := 'Entered mobile number is not registered with us.Please contact customer care.';

      else
        if ((vCustDob <> TO_CHAR(TO_DATE(P_Dob,'DD/MM/YYYY'),'DD-MON-YY')) OR (vCustDob IS Null)) then
          p_Message := 'Entered date of birth is not registered with us.Please contact customer care.';

        else
          OPEN p_Output FOR
            select vCRN as "CrnNum", vCustid as "CustId", vMobno as "MobNo", vCustname as "CustName", vCustDob as "CustDob"
              from dual;
        End if;
      End if;
    End if;
  else
    p_Message := 'Inconsistent details for entered data found. Please contact customer care';
  End if;

EXCEPTION
  WHEN NO_DATA_FOUND THEN
    p_Message := 'Unable to process your request.Please contact customer care.';
    OPEN p_Output FOR
      SELECT 1 FROM dual;
END;

如果有人能提供帮助,我真的很感激。

2 个答案:

答案 0 :(得分:1)

  • 您只需使用一个SELECT ... INTO ...并捕获异常TOO_MANY_ROWS
  • ''NULL是一回事。
  • 如果手机号码不匹配(或为空),则不会返回一行,因此检查是多余的。
  • 与出生日期相同。
  • DISTINCT 一个函数 - 它是一个适用于所有行的关键字。
  • 您将光标分配给p_output两次。此外,某些系统可能不喜欢该函数可以向游标返回不同数量的列。

所以,像这样:

create or replace PROCEDURE sp_cp_getcrnnofrmmobdob(
  P_MobileNo    IN VARCHAR2,
  P_Dob         IN VARCHAR2,
  p_Output      out SYS_REFCURSOR,
  p_Message     OUT VARCHAR2
)
IS
  v_dob     DATE := TO_DATE( p_dob, 'DD/MM/YYYY' );
  vCRN      FCH_CASTRANSACTION.NBFC_CUSTOMER_M.fw_customer_id_c%TYPE;
  vCustid   FCH_CASTRANSACTION.NBFC_CUSTOMER_M.Cust_Id_n%TYPE;
  vMobno    FCH_CASMASTER.nbfc_address_m.MOBILE%TYPE;
  vCustname FCH_CASTRANSACTION.NBFC_CUSTOMER_M.customername%TYPE;
  vCustDob  FCH_CASTRANSACTION.NBFC_CUSTOMER_M.dob%TYPE;
BEGIN
  p_Message := '';

  select distinct
         C.fw_customer_id_c,
         C.Cust_Id_n,
         c.customername,
         c.dob,
         A.MOBILE
  into   vCRN, vCustid, vMobno, vCustname, vCustDob
  from   FCH_CASTRANSACTION.NBFC_CUSTOMER_M C
         INNER JOIN FCH_CASMASTER.nbfc_address_m A
         ON ( A.BPID = C.Cust_Id_n )
  WHERE  A.mobile = P_MobileNo
  AND    TO_DATE( C.DOB, 'DD-MON-YY') = v_dob;

  IF vCRN IS NULL THEN
    p_Message := 'No data found for entered details';
    OPEN p_Output FOR
      select 1 from dual;
    RETURN;
  END IF;

  OPEN p_Output FOR
    select vCRN as "CrnNum", vCustid as "CustId", vMobno as "MobNo", vCustname as "CustName", vCustDob as "CustDob"
    from dual;
EXCEPTION
  WHEN NO_DATA_FOUND THEN
    p_Message := 'Unable to process your request.Please contact customer care.';
    OPEN p_Output FOR
      SELECT 1 FROM dual;
  WHEN TOO_MANY_ROWS THEN
    p_Message := 'Inconsistent details for entered data found. Please contact customer care';
    OPEN p_Output FOR
      SELECT 1 FROM dual;
END;

答案 1 :(得分:0)

我建议您查看两个查询中的TO_CHAR(TO_DATE(C.DOB, 'DD-MON-YY'),'DD-MON-YY')=TO_CHAR(TO_DATE(P_Dob,'DD/MM/YYYY'),'DD-MON-YY'))

  1. 根据此逻辑,您将出生日期(dob)存储为字符串。如果你这样做,那将是一种耻辱,它应该作为DATE
  2. 在数据库中
  3. 您正在将字符串转换为日期,然后再转换回字符串。在Oracle中,您可以比较日期,因此只能从列转换为DATE,而不能再转换回字符串。例如TO_DATE(column,'column format')=TO_DATE(variable,'variable format')
  4. 或者,更好的是,对于您的数据模型,请考虑转换变量输入日期字符串以匹配列字符串格式。像column = TO_CHAR(TO_DATE(variable, 'variable format'),'column format')一样。这里有两个可能的优点。首先,转换只会对提供的值发生一次,但查询永远不必对列值执行函数。如果表很大。此外,由于没有对列值执行任何功能,如果该值有一个索引,优化器可以使用它(尽管根据我对您的数据模型的猜测,这可能对您的示例没有帮助)。这里的性能改进取决于查询如何使用dob。如果Oracle按手机号码查询记录,然后按dob过滤,它应该没什么区别,但如果反过来,通过dob查找然后过滤手机号码,这可能会有很大帮助。
  5. tl; dr将日期存储为日期,将日期作为日期进行比较,尽可能避免列值上的函数