0

以下 SQL 在具有相同架构的两个表之间生成所有匹配记录,然后继续迭代存储此结果集的游标。我在此函数的末尾使用提交进行逐行插入。我的问题是如何从这种类型的查询中获得最大的性能?代码如下:

BEGIN  
DECLARE    
   CURSOR foo IS  
        SELECT * FROM tableOne to  
        WHERE EXISTS (SELECT * FROM tableTwo tt  
                       WHERE TO.FOO = TT.FOO  
                       AND TO.BAR = TT.BAR);  --THIS TAKES 5 MINUTES (66 MILLION ROWS)
     BEGIN  
           FOR nextFoo IN foo  
     LOOP  
            INSERT INTO tracker t  
               (id,foo,bar,baz)  
            VALUES(trackerSequence.nextval, nextFoo.foo,nextFoo.bar,nextFoo.baz);  
     END LOOP;   
     COMMIT;  
     END;  
END;

此查询可能需要一个多小时,我正在尝试减少与之相关的时间成本。我一般将处理 1.4 亿条记录,因此我预计此过程所需的时间会增加一倍。所有列都被索引。

版本信息:

10克10.2

4

6 回答 6

6

怎么样

INSERT INTO tracker t SELECT trackerSequence.nextVal
                            ,foo
                            ,bar
                            ,baz 
                      FROM tableOne to 
                            INNER JOIN tabletwo tt 
                         ON (to.foo = tt.foo and to.bar=tt.bar);

我想知道这是否会更好地优化。

还要确保在插入时禁用跟踪器-表索引。

于 2012-08-01T18:08:02.157 回答
3

好的,我知道你想要光标...

使用游标的唯一真正优势是每 10k 提交一次?处理这么多数据时的行以避免填满日志。

除非你真的需要游标,否则消除行处理。

insert into tracker (id, foo, bar, baz)
select trackersequence.nextval, t1.foo, t1.bar, t2.baz
from tableone t1, tabletwo t2 where 
t1.foo = t2.foo and
t1.bar = t2.bar;

建议的直接路径插入提示

insert /*+ append */ into tracker (id, foo, bar, baz)
select trackersequence.nextval, t1.foo, t1.bar, t2.baz
from tableone t1, tabletwo t2 where 
t1.foo = t2.foo and
t1.bar = t2.bar;
于 2012-08-01T18:13:33.693 回答
1
DECLARE    

CURSOR foo_cur 
IS SELECT * FROM tableOne TO  
    WHERE EXISTS (SELECT * FROM tableTwo tt  
                   WHERE TO.FOO = TT.FOO  
                   AND TO.BAR = TT.BAR);  --THIS TAKES 5 MINUTES (66 MILLION ROWS)  

TYPE foo_nt IS TABLE OF tableOne%ROWTYPE;
v_foo_nt foo_nt;

 BEGIN

  OPEN foo_cur ;
  LOOP
  FETCH foo_cur BULK COLLECT INTO v_foo_nt LIMIT 1000;

       FORALL  i IN v_foo_nt.FIRST..v_foo_nt.LAST  
         INSERT INTO tracker t  
           (id,foo,bar,baz)  
          VALUES(trackerSequence.nextval, v_foo_nt(i).foo,v_foo_nt(i).bar,v_foo_nt(i).baz);  

EXIT WHEN foo_cur%NOTFOUND;  
END LOOP; 
  CLOSE foo_cur;  
  COMMIT;  
 END;  
END;
于 2012-08-01T18:08:20.663 回答
0

首先 - 如何优化 PL/SQL 的性能:

  • 在开始加载之前禁用目标表上的索引和任何其他约束,并在完成后重新启用它们
  • 不要在最后提交 - 有提交点来释放回滚段

第二 - 不要使用 PL/SQL 进行插入。使用 BulkLoading(正如一些评论已经建议的那样)。如果你用谷歌搜索“oracle sql loader”,你可以很容易地找到关于 BulkLoading 的大量信息

于 2012-08-01T18:07:46.260 回答
0

BITMAP INDEXES通过结合使用 DPL(直接路径加载)(即使用提示),我几乎总能在此类批量数据插入中获得更好的性能/*+ APPEND+/

TT.FOO, TT.BAR我还假设这样您将在和上都有适当的索引TO.FOO, TO.BAR。所以有人认为

INSERT /*+ APPEND*/
  INTO TRACKER T
SELECT trackerSequence.nextval, to.foo,to.bar,to.baz
  FROM tableOne to  
  WHERE EXISTS (SELECT 'x' 
                  FROM tableTwo tt  
                 WHERE TO.FOO = TT.FOO  
                   AND TO.BAR = TT.BAR);

另外-请记住,EXIST在某些情况下,该子句可能会咬你。因此,您可能想要使用简单的外连接。

INSERT /*+ APPEND*/
  INTO TRACKER T
SELECT DISTINCT trackerSequence.nextval, to.foo,to.bar,to.baz
  FROM tableOne to , tableTwo tt
  WHERE TO.FOO = TT.FOO  
    AND TO.BAR = TT.BAR;

请记住 - DPL(直接路径加载)不会总是提高查询的性能,如果您的表正确分区,它可能会提高(或帮助)。

尝试对这些查询进行解释计划以找出最好的。此外,(正如已经提到的答案之一)最后不要提交,但也不要在每条记录上提交。建议使用类似于 while using LIMIT XXXXwhile BULK COLLECTing 的自定义提交点。您的提交点将决定您的ROLLBAK分段有多大。您还可以在程序上(即在 PLSQL BLOCK 中)使用您的自定义提交点(就像计数器一样简单)。

查询性能还取决于HWM您的表(具体而言),您几乎总是希望HWM在表下执行。虽然TRUNCATE放在TRACKER桌子上有助于实现这一点,但以前的数据会丢失,所以这在这里很难解决。按照此AskTom链接了解如何查找HWM

于 2012-08-01T19:04:38.790 回答
0

我发现以下将在大约 49 分钟内完成 1.3 亿次插入。

INSERT INTO tracker t  
    SELECT * FROM tableOne to  
        WHERE NOT EXISTS (SELECT * FROM tableTwo tt  
                       WHERE TO.FOO = TT.FOO  
                       AND TO.BAR = TT.BAR);
于 2012-08-03T14:15:07.053 回答