【问题标题】:Are there any impact of update statement on for loop statement in oracle?更新语句对oracle中的for循环语句有影响吗?
【发布时间】:2016-07-19 10:42:40
【问题描述】:

我已经嵌套了迭代同一张表的 for 循环。在内部循环中,我更新了同一张表中的一列。但是在 for 循环条件下,我检查了更新的列,我需要在开始时而不是动态地检查此列,所以我的 for 循环迭代可能会大大减少。

我这样做是正确的还是 for 语句不会看到更新的列?

declare
control number(1);
dup number(10);
res varchar2(5);--TRUE or FALSE

BEGIN
dup :=0;
control :=0;
FOR aRow IN (SELECT MI_PRINX, geoloc,durum, ROWID FROM ORAHAN where durum=0)    
LOOP
 FOR bRow IN (SELECT MI_PRINX, geoloc, ROWID FROM ORAHAN WHERE ROWID>aRow.ROWID AND durum=0)
  LOOP
    BEGIN
       --dbms_output.put_line('aRow' || aRow.Mi_Prinx || ' bRow' || bRow.Mi_Prinx);
    select SDO_GEOM.RELATE(aRow.geoloc,'anyinteract', bRow.Geoloc,0.02) into res from dual;
    if (res='TRUE')
      THEN 
        Insert INTO ORAHANCROSSES values (aRow.MI_PRINX,bRow.MI_PRINX);
        UPDATE ORAHAN SET DURUM=1 where rowid=bRow.Rowid; 
        control :=1;
        --dbms_output.put_line(' added');
    END IF;
    EXCEPTION
      WHEN DUP_VAL_ON_INDEX
        THEN
          dup := dup+1;
          --dbms_output.put_line('duplicate');
          --continue;
    END;
  END LOOP;
  IF(control =1)
    THEN
      UPDATE ORAHAN SET DURUM=1 WHERE rowid=aRow.Rowid;
  END IF;
  control :=0;
END LOOP;
dbms_output.put_line('duplicate: '||dup);
END ;

注意:我使用 oracle 11g 和 pl/sql developer 对不起我的英语。

【问题讨论】:

  • ROWID > aRow.ROWID 试图达到什么目的? Oracle 中的ROWID 是(或多或少)随机字符串。 ROWID > aRow.ROWID 的结果未确定。除非您锁定记录,否则给定记录的 ROWID 甚至可能会更改。但是,手动锁定行通常是不好的做法。
  • 我意识到我在使用 rowid 时出错了。我的目的是在外循环中一一检查所有行,但另一方面;在内部循环中,我只需要从外部循环中的选定行中检查更多行。

标签: oracle


【解决方案1】:

是的,FOR 语句将看不到更新后的 DURUM 列,因为 FOR 语句将看到所有数据,就像查询开始时一样!这称为读一致性,Oracle 通过使用生成的 UNDO 数据来实现这一点。这意味着随着 FOR 循环的推进和基表的更新,它将有越来越多的工作要做(==运行速度变慢)!

这也意味着当 UNDO 表空间耗尽时,您的实现最终会遇到 ORA-01555: snapshot too old 错误。

使用 SQL MERGE 语句可能会更好,该语句也应该运行得更快。

例如:

Merge Into ORAHANCROSSES C
Using (Select aROW.MI_PRINX  aROW_MI_PRIX, 
              aROW.GEOLOC    aROW_GEOLOC,
              bROW.MI_PRINX  bROW_MI_PRIX, 
              bROW.GEOLOC    bROW_GEOLOC,
              SDO_GEOM.RELATE(aRow.geoloc,'anyinteract', bRow.Geoloc,0.02) RES
       From   ORAHAN aROW,
              ORAHAN bROW
       Where  aROW.ROWID < bROW.ROWID
       ) Q
On    (C.MI_PRIX1 = Q.aROW_MI_PRIX
  and  C.MI_PRIX2 = Q.bROW_MI_PRIX)
When Matched Then
     Delete Where Q.RES = 'FALSE'
When Not Matched Then
     Insert Values (Q.aROW_MI_PRIX, Q.bROW_MI_PRIX)
     Where Q.RES = 'TRUE'
;

我不确定你想通过ROWID&gt;aRow.ROWID 完成什么

要使用特定顺序(在本例中为 MI_PRINX),请使用以下技术:

Merge Into ORAHANCROSSES C
Using (With D as (select T.*, ROWNUM RN from (select MI_PRINX, GEOLOC from ORAHAN order by MI_PRINX) T)
       Select aROW.MI_PRINX  aROW_MI_PRIX, 
              aROW.GEOLOC    aROW_GEOLOC,
              bROW.MI_PRINX  bROW_MI_PRIX, 
              bROW.GEOLOC    bROW_GEOLOC,
              SDO_GEOM.RELATE(aRow.geoloc,'anyinteract', bRow.Geoloc,0.02) RES
       From   D aROW,
              D bROW
       Where  aROW.RN < bROW.RN
       ) Q
On    (C.MI_PRIX1 = Q.aROW_MI_PRIX
  and  C.MI_PRIX2 = Q.bROW_MI_PRIX)
When Matched Then
     Delete Where Q.RES = 'FALSE'
When Not Matched Then
     Insert Values (Q.aROW_MI_PRIX, Q.bROW_MI_PRIX)
     Where Q.RES = 'TRUE'
;

如果查询时间过长,您可以select * from v$session_longops where seconds_remaining &gt;0 了解查询何时完成。

【讨论】:

  • 我必须在外循环中一一循环所有行。但是在内部循环中,我只需要检查更多的行(大于外行.ID)。我想我为此使用rownum还是什么?更新语句在合并语句中有效吗?
  • 我添加了“Where aROW.ROWID
  • 我的表有大约 40 万条记录,我等待 50 分钟执行,但没有结束。有什么建议吗?
  • 看我的更新,如果我是正确的,你将计算 800 亿个组合
  • 我要试试。顺便说一句,“When Matched Then Delete Where 子句给出错误为'缺少关键字'”但我删除了该部分,然后它才起作用。感谢您的所有帮助。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2011-02-24
  • 2015-10-30
  • 1970-01-01
  • 2018-07-31
  • 1970-01-01
  • 1970-01-01
  • 2011-08-17
相关资源
最近更新 更多