0

次のSQLは、同一のスキーマを持つ2つのテーブル間で一致するすべてのレコードを生成し、この結果セットを格納するカーソルを反復処理します。この関数の最後にコミットを使用して、行ごとに挿入を行います。私の質問は、このタイプのクエリから最大のパフォーマンスを得るにはどうすればよいですか?コードは次のとおりです。

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時間以上かかる場合があり、それに関連する時間コストを削減しようとしています。私は一般的に1億4000万レコードを処理するので、このプロセスにかかる時間は2倍になると予想しています。すべての列にインデックスが付けられます。

バージョン情報:

10g 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

OK、カーソルが欲しかったのはわかっています...

カーソルを使用する唯一の本当の利点は、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

私は、以下が約49分で1億3000万の挿入を行うことを発見しました。

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 に答える
0

まず、PL/SQLのパフォーマンスを最適化するにはどうすればよいですか。

  • ロードを開始する前にターゲットテーブルのインデックスやその他の制約を無効にし、完了後に再度有効にします
  • 最後にコミットしないでください-ロールバックセグメントを解放するためのコミットポイントがあります

2番目-PL/SQLで挿入を行わないでください。BulkLoadingを使用します(すでにいくつかのコメントで示唆されているように)。「oraclesqlloader」をグーグルで検索すると、BulkLoadingに関する多くの情報を簡単に見つけることができます。

于 2012-08-01T18:07:46.260 に答える
0

BITMAP INDEXESDPL(Direct Path Load)を組み合わせて使用​​することにより、つまりヒントを使用することにより、このようなバルクデータ挿入でほとんどの場合パフォーマンスが向上しました/*+ 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(ダイレクトパスロード)は、クエリのパフォーマンスを常に向上させるとは限りません。テーブルが適切にパーティション化されていると、向上(または役立つ)する可能性があります。

これらのクエリについてExplainプランを試して、最適なものを見つけてください。また、(すでに述べた答えの1つとして)最後にコミットしませんが、すべてのレコードにもコミットしません。ingLIMIT XXXX中に使用しているときと同様のカスタムコミットポイントを使用することをお勧めします。BULK COLLECTコミットポイントは、ROLLBAKセグメントの大きさを決定します。カスタムのコミット・ポイント(カウンターのように単純)を手続き的に(つまり、PLSQLブロックで)使用することもできます。

クエリのパフォーマンスは、テーブルの(具体的には)にも依存しHWMます。ほとんどの場合HWM、テーブルの下で実行する必要があります。テーブルTRUNCATE上ではTRACKERこれを達成するのに役立ちますが、それに関する以前のデータは失われるため、これがここでの解決策になることはほとんどありません。を見つける方法については、このAskTomHWMリンクをたどってください。

于 2012-08-01T19:04:38.790 に答える