oracle12c 一个存储过程放job中执行效率超级慢,plsql执行很快

时间:2021-08-11 16:48:10
oracle的一个存储过程放在job中自动执行效率很慢,几秒钟处理一条记录,如果放到plsql中或者sqlplus中去执行速度很快,1万条记录大约在20秒钟;
数据库时oracle12c,rac环境,两个节点,服务器内存有32g,cpu多核心的,服务器及配置上应该没有问题,没有死锁,open_cursor设置为1000,配置如下:

oracle12c 一个存储过程放job中执行效率超级慢,plsql执行很快

oracle12c 一个存储过程放job中执行效率超级慢,plsql执行很快
我需要每分钟执行一次这个存储过程,但是现在每次执行都需要好长时间,处理的数据量也不是很大。
系统在oracle10g/11g下面都很正常,就是12c的rac环境下这样,实在是不知道什么原因。
哪位高人指点下,不胜感激。

7 个解决方案

#1


内存32g有点少哦,一般都在128g以上~

#2


发下你存储过程,看下代码如何?

#3


PROCEDURE autoprocuploadconsumerec
    AS
        
        out_msg         VARCHAR2 (1000);
        out_result      NUMBER;
        vplanstoptime   VARCHAR2 (128);
        vcount          NUMBER;
        visbalance      NUMBER;
        n_opcount       NUMBER;
        n_oddfare       NUMBER;
        n_subopcount    NUMBER;
        n_suboddfare    NUMBER;

        CURSOR c1
        IS
            SELECT *
              FROM (  SELECT *
                        FROM t_xfjla
                    ORDER BY a.id)
             WHERE ROWNUM < 800;
    BEGIN
        out_msg := '';
      
         dbms_output.put_line( 'START PROCESS _CONSUME'|| to_char(SYSTIMESTAMP,'yy-mm-dd hh24:mi:ss:ff3') );

       
            FOR c1_rec IN c1
            LOOP
                SELECT NVL (COUNT (*), 0)
                  INTO vcount
                  FROM base_customers a
                 WHERE     a.customerid = c1_rec.customerid
                       AND a.dpid = c1_rec.dpid;

  
                --如果为正式账户,则锁住base_customers表中的行
                IF vcount > 0
                THEN
                    SELECT a.opcount,
                           a.oddfare,
                           a.subopcount,
                           a.suboddfare
                      INTO n_opcount,
                           n_oddfare,
                           n_subopcount,
                           n_suboddfare
                      FROM base_customers a
                     WHERE     a.customerid = c1_rec.customerid
                           AND a.dpid = c1_rec.dpid
                    FOR UPDATE   OF
                        a.opcount, a.oddfare, a.subopcount, a.suboddfare skip locked ;
                END IF;
          
                SELECT NVL (COUNT (*), 0)
                  INTO vcount
                  FROM rec_writeoff a
                 WHERE     a.customerid = c1_rec.customerid
                       AND a.dpid = c1_rec.dpid;

                
       
                    pkg_rec_cust_acc.processconsumerec (c1_rec.customerid,                                                        
                                                        out_msg,
                                                        out_result);
                 
                    --记录处理成功,删除上传记录
                    DELETE rec_upload_consume
                     WHERE id = c1_rec.id;
 
                      dbms_output.put_line( 'END PROCESS REC_UPLOAD_CONSUME'|| to_char(SYSTIMESTAMP,'yy-mm-dd hh24:mi:ss:ff3') );
                COMMIT;
            END LOOP;
          
       
    EXCEPTION
        WHEN OTHERS
        THEN
            ROLLBACK;
            out_msg := out_result || '_' || out_msg || '_' || SQLERRM;
            out_result := -1;
              dbms_output.put_line( 'proceupdateoldflag' || OUT_MSG || to_char(SYSTIMESTAMP,'yy-mm-dd hh24:mi:ss:ff3') );
           
    END;

我用的exec  dbms_scheduler做的job自动1分钟执行一次,目前每次总超过1分钟,plsql中执行速度很快



#4


内存好像是96g,足够用了

#5


job执行的时候,看看有没有锁,看看v$session_wait有什么等待事件

#6


 一分钟执行一次为什么还要一条条记录执行,直接一批执行不就好啦?而且你这种没加监控时间,你自己都不知道你这个sql执行那一步比较慢

#7


id 有索引没有,加个索引看看! base_customers 查询慢步 ,和 pkg_rec_cust_acc.processconsumerec 又是什么过程, FOR UPDATE   OF 不用可以不,加个日志运行记录临时表分段记录记录时间为毫秒,看看运行到哪个代码段慢了,就分析一下!

#1


内存32g有点少哦,一般都在128g以上~

#2


发下你存储过程,看下代码如何?

#3


PROCEDURE autoprocuploadconsumerec
    AS
        
        out_msg         VARCHAR2 (1000);
        out_result      NUMBER;
        vplanstoptime   VARCHAR2 (128);
        vcount          NUMBER;
        visbalance      NUMBER;
        n_opcount       NUMBER;
        n_oddfare       NUMBER;
        n_subopcount    NUMBER;
        n_suboddfare    NUMBER;

        CURSOR c1
        IS
            SELECT *
              FROM (  SELECT *
                        FROM t_xfjla
                    ORDER BY a.id)
             WHERE ROWNUM < 800;
    BEGIN
        out_msg := '';
      
         dbms_output.put_line( 'START PROCESS _CONSUME'|| to_char(SYSTIMESTAMP,'yy-mm-dd hh24:mi:ss:ff3') );

       
            FOR c1_rec IN c1
            LOOP
                SELECT NVL (COUNT (*), 0)
                  INTO vcount
                  FROM base_customers a
                 WHERE     a.customerid = c1_rec.customerid
                       AND a.dpid = c1_rec.dpid;

  
                --如果为正式账户,则锁住base_customers表中的行
                IF vcount > 0
                THEN
                    SELECT a.opcount,
                           a.oddfare,
                           a.subopcount,
                           a.suboddfare
                      INTO n_opcount,
                           n_oddfare,
                           n_subopcount,
                           n_suboddfare
                      FROM base_customers a
                     WHERE     a.customerid = c1_rec.customerid
                           AND a.dpid = c1_rec.dpid
                    FOR UPDATE   OF
                        a.opcount, a.oddfare, a.subopcount, a.suboddfare skip locked ;
                END IF;
          
                SELECT NVL (COUNT (*), 0)
                  INTO vcount
                  FROM rec_writeoff a
                 WHERE     a.customerid = c1_rec.customerid
                       AND a.dpid = c1_rec.dpid;

                
       
                    pkg_rec_cust_acc.processconsumerec (c1_rec.customerid,                                                        
                                                        out_msg,
                                                        out_result);
                 
                    --记录处理成功,删除上传记录
                    DELETE rec_upload_consume
                     WHERE id = c1_rec.id;
 
                      dbms_output.put_line( 'END PROCESS REC_UPLOAD_CONSUME'|| to_char(SYSTIMESTAMP,'yy-mm-dd hh24:mi:ss:ff3') );
                COMMIT;
            END LOOP;
          
       
    EXCEPTION
        WHEN OTHERS
        THEN
            ROLLBACK;
            out_msg := out_result || '_' || out_msg || '_' || SQLERRM;
            out_result := -1;
              dbms_output.put_line( 'proceupdateoldflag' || OUT_MSG || to_char(SYSTIMESTAMP,'yy-mm-dd hh24:mi:ss:ff3') );
           
    END;

我用的exec  dbms_scheduler做的job自动1分钟执行一次,目前每次总超过1分钟,plsql中执行速度很快



#4


内存好像是96g,足够用了

#5


job执行的时候,看看有没有锁,看看v$session_wait有什么等待事件

#6


 一分钟执行一次为什么还要一条条记录执行,直接一批执行不就好啦?而且你这种没加监控时间,你自己都不知道你这个sql执行那一步比较慢

#7


id 有索引没有,加个索引看看! base_customers 查询慢步 ,和 pkg_rec_cust_acc.processconsumerec 又是什么过程, FOR UPDATE   OF 不用可以不,加个日志运行记录临时表分段记录记录时间为毫秒,看看运行到哪个代码段慢了,就分析一下!