ORACLE - 如何改进此查询?

时间:2016-07-17 16:00:34

标签: oracle plsql

我有两张桌子。一个是空的,另一个有大约2万个记录。在这些记录中有几何列,它使用Oracle的SDO_PACKAGE。我必须找到这些记录之间的交叉点。 我写的pl / sql查询对我来说足够了,但只有2千条记录它消耗了20分钟。我尝试完成执行,但在330分钟内仍然会继续。因此,我可以改进这些查询以加快执行速度。

子问题:在插入部分,我应该使用缓冲区,最后通过批量插入插入还是其他什么?

注意:我使用的是oracle 11g和pl / sql开发人员。 FirstTable有20000条记录。 (几何) SecondTable初始为空。

declare
control1 number(1);
control2 number(1);
resultForStart varchar2(5);
resultForEnd varchar2(5);
BEGIN
FOR aRow IN (SELECT MI_PRINX, SDO_LRS.geom_segment_start_pt(geoloc) as startpoint, SDO_LRS.geom_segment_end_pt(geoloc) as endpoint FROM FirstTable)
 LOOP
  control1 :=0;
  control2 :=0; 
  FOR bRow IN (SELECT * FROM SecondTable)
   LOOP
    select SDO_GEOM.RELATE(aRow.Startpoint,'anyinteract', SDO_LRS.geom_segment_start_pt(bRow.Geoloc),0.02) into resultForStart from dual;
    select SDO_GEOM.RELATE(aRow.Endpoint,'anyinteract', SDO_LRS.geom_segment_end_pt(bRow.Geoloc),0.02) into resultForEnd from dual;
    if (resultForStart='TRUE' AND control1=0 )
     THEN 
      UPDATE SecondTable SET COUNTER=(bRow.Counter+1) 
            WHERE MI_PRINX=bRow.Mi_Prinx AND STARTEND=bRow.Startend;
    control1 :=1;          
    END IF;
    if (resultForEnd='TRUE' AND control2=0)
     THEN 
      UPDATE SecondTable SET COUNTER=(bRow.Counter+1)
             WHERE MI_PRINX=bRow.Mi_Prinx AND STARTEND=bRow.Startend;
    control2 :=1;
    END IF;           
    EXIT WHEN (control1 > 0 AND control2>0);
   END LOOP;    
  if (control1 = 0) 
   THEN    
    Insert INTO SecondTable (MI_PRINX,STARTEND,GEOLOC) values (aRow.Mi_Prinx,'s',aRow.Startpoint);--default Counter 1
  END IF;
  if (control2 = 0)
   THEN
    Insert INTO SecondTable (MI_PRINX,STARTEND,GEOLOC) values (aRow.Mi_Prinx,'e',aRow.Endpoint);--default Counter 1
  END IF;
  control1 :=0;
  control2 :=0; 
 END LOOP; 
END;

1 个答案:

答案 0 :(得分:2)

这里有提示:您似乎正在从表中读取行,然后更新它们。

FOR bRow IN (SELECT * FROM SecondTable)
   LOOP
    ...
    if (resultForStart='TRUE' AND control1=0 )
     THEN 
      UPDATE SecondTable SET COUNTER=(bRow.Counter+1) 
            WHERE MI_PRINX=bRow.Mi_Prinx AND STARTEND=bRow.Startend;

如果必须这样做,请改用rowid:

FOR bRow IN (SELECT * FROM SecondTable)
   LOOP
    ...
    if (resultForStart='TRUE' AND control1=0 )
     THEN 
      UPDATE SecondTable SET COUNTER=(bRow.Counter+1) 
            WHERE ROWID=bRow.rowid;

这将为您提供查找要更新的行的最快方法。