甲骨文 - 表现缓慢

时间:2017-01-25 22:01:10

标签: oracle stored-procedures plsql

以下程序需要将近5个小时才能完成130000条记录。尝试过优化它。有没有办法优化它? 如果我在每个"之后为所有人做出承诺" ,这会提高性能吗? 此外,我已经给出了1000条记录的限制,所以这里是提交1000条记录处理还是计数为0? 数据库版本:oracle 10g

我正在运行以下程序:

create or replace PROCEDURE       WeeklyClearQwAcctActivityLoad
AS


   v_no_of_Days_retention number;
   jobname      VARCHAR2 (30);
   loadstartdt  DATE;
   rcdcnt number;
   errorcode                 NUMBER;
   errormsg                  VARCHAR2 (100);

   /* Identify those records for which all CUST_ACCT_ID under the same Parent_id are closed (before retention days ) */
   CURSOR getdataforhist
   IS
        select /*+ parallel(qa2,128) */ CUST_ACCT_ID from qw_account qa2
        where exists
            ( select /*+ parallel(qaa2,128) */ 1 from QW_ACCT_ACTIVITY qaa2
                                                   where qaa2.cust_acct_id = qa2.cust_acct_id
                                                     and qaa2.actvy_end_date < sysdate - v_no_of_Days_retention
                                                 )
        and not exists
                 (
                    select 1 from (
                                    select /*+ parallel(qa,128) */  qa.PARENT_ID pidd from qw_account qa
                                     where  exists
                                                ( select /*+ parallel(qaa,128) */ 1 from QW_ACCT_ACTIVITY qaa
                                                   where qaa.cust_acct_id = qa.cust_acct_id
                                                     and qaa.actvy_end_date > sysdate - v_no_of_Days_retention
                                                 )
                                   ) pp where pp.pidd = qa2.PARENT_ID
                  );

   TYPE t_getDataForHist IS TABLE OF qw_acct_activity.cust_acct_id%TYPE;
   l_getDataForHist   t_getDataForHist;

   CURSOR orph_product
  IS
  SELECT  /*+ parallel( ram , 128) */ ram.rcr_prod_acct_id
    FROM  rcr_acct_mapping ram
   WHERE  1=1
     AND  ram.cust_acct_id IS NOT NULL
     AND  EXISTS
              ( SELECT /*+ parallel( rap , 128) */ 1
                        FROM  rcr_acct_profile rap
                         WHERE  rap.rcr_prod_acct_id = ram.rcr_prod_acct_id
                   AND  rap.cust_acct_id = ram.cust_acct_id
                       AND  rap.prod_acct_status in ('ACTIVE','INACTIVE','SUSPENDED')
               )
     AND  NOT EXISTS
                  ( SELECT /*+ parallel( qaa , 128 */  1
                      FROM  qw_acct_activity qaa
                     WHERE  qaa.cust_acct_id = ram.cust_acct_id
                   );

  TYPE  t_orph_product is table of rcr_acct_mapping.rcr_prod_acct_id%TYPE;
  l_orph_product t_orph_product;
  cnt number default 0;

BEGIN
   jobname := 'WEEKLY_CLEAN_QW_ACCT_ACTIVITY';
   loadstartdt := SYSDATE;
   rcdcnt := 0;

   INSERT INTO rcr_stage_audit (job_name,load_start_date,load_end_date,record_cnt,processed,process_date,process_cnt,ignore_cnt)
          VALUES (jobname,loadstartdt,NULL,NULL,'N',loadstartdt,NULL,NULL );
   COMMIT;

         BEGIN
             SELECT VALUE into v_no_of_Days_retention
               FROM rcr_online_svc_app_config
              WHERE NAME = 'noofdaystoenddateqwacctactivity';
          EXCEPTION
             WHEN NO_DATA_FOUND
             THEN
                errorcode := SQLCODE;
                errormsg := 'no of days to end date qw_accta_ctivity is not defined in rcr_code_translation table';
                raise_application_error (-20101, errorcode || ' - ' || errormsg, TRUE);
          END;

   OPEN getDataForHist;

   LOOP
      FETCH getdataforhist  BULK COLLECT INTO l_getdataforhist LIMIT 1000;
      --EXIT WHEN getdataforhist%NOTFOUND   ;
    EXIT WHEN l_getdataforhist.COUNT = 0;

        -- FORALL indx IN 1 .. l_getdataforhist.count
        -- insert into TEMPSLOT (CUST_ACCT_ID) values ( l_getdataforhist(indx) ) ;

         FORALL indx1 IN 1 .. l_getdataforhist.count
         INSERT INTO qw_acct_activity_hist
               SELECT qaa.*, SYSDATE
                 FROM qw_acct_activity qaa
                WHERE CUST_ACCT_ID = ( l_getdataforhist(indx1) );

          FORALL indx2 IN 1 .. l_getdataforhist.count
            DELETE FROM qw_acct_activity
                WHERE CUST_ACCT_ID = ( l_getdataforhist(indx2) );

                rcdcnt := rcdcnt + sql%rowcount;

    COMMIT;
   END LOOP;
  CLOSE getDataForHist;


  --- Clean porduct tables for orphan CUST_ACCT_ID

  OPEN orph_product;
  LOOP
  FETCH orph_product BULK COLLECT INTO l_orph_product LIMIT 1000;
  EXIT WHEN l_orph_product.COUNT = 0;

       FORALL indx10 IN 1 .. l_orph_product.COUNT
         INSERT INTO rcr_acct_mapping_hist
               SELECT a.*
                 FROM rcr_acct_mapping a
                WHERE rcr_prod_acct_id = ( l_orph_product(indx10) );

       FORALL indx11 IN 1 .. l_orph_product.COUNT
         DELETE FROM rcr_acct_mapping WHERE rcr_prod_acct_id = ( l_orph_product(indx11) );

       FORALL indx12 IN 1 .. l_orph_product.COUNT
         DELETE FROM rcr_addt_acct_prof_detail WHERE rcr_prod_acct_id = ( l_orph_product(indx12) );

       FORALL indx13 IN 1 .. l_orph_product.COUNT
         DELETE FROM rcr_acct_profile_detail WHERE rcr_prod_acct_id = ( l_orph_product(indx13) );

       FORALL indx14 IN 1 .. l_orph_product.COUNT
         DELETE FROM rcr_acct_profile WHERE rcr_prod_acct_id = ( l_orph_product(indx14) );
     COMMIT;

  END LOOP;

  close orph_product;

  UPDATE rcr_stage_audit
         SET load_end_date = SYSDATE,
             record_cnt =  rcdcnt,
             processed = 'Y'
       WHERE job_name = jobname
         AND process_date = loadstartdt
         AND load_start_date = loadstartdt;

  COMMIT;


EXCEPTION
   WHEN OTHERS
   THEN
        errorcode := SQLCODE;
        errormsg :=  substr(sqlerrm,1,255);
        raise_application_error (-20102, errorcode || ' - ' || errormsg, TRUE);
END WeeklyClearQwAcctActivityLoad;

2 个答案:

答案 0 :(得分:3)

我向你推荐的一个建议是避免显式循环和游标。它会导致性能不佳,尤其是当您可以直接使用

insert into <table_name>(columns) select <your_query_goes_here>

这肯定会比循环结构执行得更快。实际上,您可以使用一百万条记录生成的表中的简单基准重现此行为。

因此,简而言之,请尽量避免循环,并且您的代码看起来也会更具可读性且不易出错。

我做了一次基准测试,其中1000万条记录中只有大约12,000条记录需要更新,显式循环与隐式循环导致的时间是1分10秒v / s 1秒。

答案 1 :(得分:0)

使用oraclebug或dbms_monitor等oracle工具跟踪它,并使用tkprof或其他分析工具检查跟踪文件。如下所示:

1.提取sid

2.在sqlplus中运行:oradebug setorapid xxxx

3.在sqlplus中运行:oradebug tracefile_name

4.在os运行完成后,在跟踪文件上运行tkprof。(其他工具也可用)。

5.在跟踪文件中检查长节并处理它们

相关问题