2012-01-20 24 views
4

私は単純なPL/SQLプロシージャを1つのカーソルで持っています。それを反復処理します。各反復では、(ビジネスロジックをデータに実行した後に)UPDATE文を作成します。Oracle PL/SQLの遅延更新

しかし、反復がたくさんある場合(数万)、すべての反復で1つのUPDATE文があるため、これは非常に遅くなる可能性があります。

これらの更新を何らかの形で「遅延」させて、すべてを一度に(したがってずっと速く)実行する方法はありますか?

編集:Oracleの11

+0

問題は、Oracleがロールバック・セグメントを維持していることです。 1つのトランザクションで変更が多いほど、遅くなります。ビジネスロジックを分割し、1000回の更新ごとに 'COMMIT; 'を追加できませんか? – sjngm

+2

@sjngm、これは一般的に悪い考えです。 Tom Kyteには、http://asktom.oracle.com/pls/apex/f?p=100:11:0::::P11_QUESTION_ID:4951966319022など、十分な説明があります。 – DCookie

+0

@snjgmの場合、ロールバック・セグメント、イテレーションとセレクトによって発生するロールバック・セグメントのために減速しません。ロールバック・セグメントの更新は、同じ答えを出すためにここに来た – steve

答えて

11

あなたが(すべて一緒forループ回避)ストレートSQLを使用する方法を見つけ出すことができない場合、あなたはおそらくPL/SQLのBULKコレクション機能を使用してパフォーマンスを向上させることができるようになります。

Example article here.

構文抜粋

LOOP 
    FETCH c_orders 
    BULK COLLECT INTO v_order_ids, v_currency_codes, v_amounts_local 
    LIMIT 100; 
    EXIT WHEN v_row_count = c_orders%ROWCOUNT; 
    v_row_count := c_orders%ROWCOUNT; 
    FOR i IN 1..v_order_ids.count LOOP 
     v_amounts_usd(i) := currency_convert (v_amounts_local(i), 
              v_currency_codes(i)); 
    END LOOP; 
    FORALL i IN 1..v_order_ids.count 
     UPDATE open_orders /* bulk bind */ 
     SET amount_usd = v_amounts_usd(i) 
     WHERE order_id = v_order_ids(i); 
    END LOOP; 
+0

+1と聞こえて実行される他の作業と比較して無視できる程度です。 forall http://www.dba-oracle.com/oracle_tips_rittman_bulk%20binds_FORALL.htmの他の記事 – bpgergo

1

ですべての可能な場合は、更新文でビジネスロジックを実行するようにしてください。それはずっと速くなるでしょう。

2

私は問題の分析を見ませんが、私は多くの前提と結論に飛びつく人々を見ています。私は次のことをお勧めし、より体系的なアプローチを取得するには:更新ジョブは、時間のほとんどは、更新ジョブがある前

  • は、セッションレベルの統計情報を取得する費やされている場所を確認するために実行したときに

    • は、セッションのための10046レベルのトレースを有効にします実行して以降。

    ほとんどの時間を費やして実際の問題に取り組んでいます。