暂无图片
暂无图片
暂无图片
暂无图片
暂无图片

Oracle 性能问题/会话挂起

askTom 2018-04-18
245

问题描述

嗨,汤姆,

我有一张表有大约500万条记录。
表结构:
DESC rpt _ msg _ 更改

Name       Null     Type           
---------- -------- -------------- 
OID      NOT NULL NUMBER         
PRODUCT    NOT NULL VARCHAR2(20)   
OPERATION  NOT NULL CHAR(1)        
STATUS     NOT NULL VARCHAR2(30)



我需要为状态 = 'AVAILABLE' 的每个记录调用一个过程,然后在其他表上进行一些压缩/插入/删除,然后将状态标记为 “已处理” 或 “失败”。我正在使用以下脚本调用:

DECLARE 
......

 CURSOR c1 IS
   select distinct PRODUCT, OID 
     from RPT_MSG_CHANGE WHERE STATUS='AVAILABLE' ORDER BY OID; 
BEGIN 
FOR v1 IN c1 LOOP
        BEGIN 
              pkg_rpt_asr_orders.proc_process_oid(v1.OID, l_data_ord_tbl);  --- calling procedure
    ..........
    ..........
    .......... ----Rest Code here
 END;
END LOOP;    
    COMMIT; 
END; 



现在,我在plsql块上方运行,该块执行大约20 k条具有可用状态的记录的过程。在mid中 (假设处理5k记录后),如果我想停止执行,我只需将状态更新为 “processed” 的表。现在,我不确定为什么会话仍在运行,并且几乎需要处理每个记录所需的时间。

你能不能让我知道oracle在这种情况下的行为,它是简单地打开一个缓冲区-> 复制其中的所有记录-> 处理缓冲区中的所有记录 (不管主表记录更新) 还是在后台有一些其他的动作?

谢谢
阿米特

专家解答

所以在第二个会话中,你运行:

update RPT_MSG_CHANGE 
set    status = 'PROCESSED'
where  status = 'AVAILABLE';
commit;


希望您的流程将没有更多的行要处理,因此停止?

不会那样做的...

记住:

光标的结果在您打开时是固定的。其他事务保存的任何更改对它来说都是不可见的!

当所有行的y = 1时,下面的示例打开游标。然后,它使用单独的事务将所有y值设置为零。

完成此操作后,它将显示光标的内容。但是结果与时间一致before然后更新。所以你看到了所有的表的行!

只有在关闭并重新打开光标后,您才能看到更新的效果:

create table t (
  x int, y int
);

insert into t 
  select level, 1 
  from   dual connect by level <= 5;
commit;

declare
  type cur_tp is ref cursor return t%rowtype;

  cur cur_tp;
  rw t%rowtype;
    
  procedure upd_t as
    pragma autonomous_transaction;
  begin
    
    update t
    set    y = 0;
    
    commit;
    
  end upd_t;
  
  procedure display_rows ( c sys_refcursor ) as
    rw cur%rowtype;
  begin
  
    loop
      fetch c into rw;
      exit when c%notfound;
      
      dbms_output.put_line ( rw.x );
      
    end loop;
  
  end display_rows;
  
begin
  open cur for select * from t where y = 1;
  
  upd_t;
  dbms_output.put_line ( '*** 1st try ***' );
  display_rows ( cur );
  
  close cur;
  
  open cur for select * from t where y = 1;
  dbms_output.put_line ( '*** 2nd try ***' );
  display_rows ( cur );
  
  close cur;
end;
/

*** 1st try ***
1
2
3
4
5
*** 2nd try ***


所以你的代码仍然在处理所有20k个可用行。如果你想阻止它,你需要要么:

-杀了它
-更改代码以具有 “停止处理” 标志,您可以在循环期间从另一个表中查找值。

更改代码是更好的选择;) 在执行此操作时,请切换到批量处理。这应该有助于它运行得更快:

http://www.oracle.com/technetwork/issue-archive/2008/08-mar/o28plsql-095155.html
「喜欢这篇文章,您的关注和赞赏是给作者最好的鼓励」
关注作者
【版权声明】本文为墨天轮用户原创内容,转载时必须标注文章的来源(墨天轮),文章链接,文章作者等基本信息,否则作者和墨天轮有权追究责任。如果您发现墨天轮中有涉嫌抄袭或者侵权的内容,欢迎发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

评论