2016-09-23 7 views
0

私は数百万の行を含むテーブルを更新する必要があります。アップデートはかなり簡単ですが、何百万ものレコードが変更されるので、何が最善の解決策だろうと思います。Oracle大規模な単一の更新または小さなバッチの更新?

  • 大きなアップデートを1回実行します。
  • テーブルを更新し、bulk collect/forallステートメントを使用して小さなバッチで変更をコミットします。

私は最初の解決策に行くだろうが、同僚はバッチでそれを行うように提案しているので、テーブルにアクセスする他のセッションはブロックされません。

どのソリューションが優れていますか?

おかげで、

+4

[頻繁なコミットにトム・カイトさんのコメント](https://asktom.oracle.com/pls/apex/f?p=100:11:0::::P11_QUESTION_ID:4951966319022):「*です間違っている、間違っている、間違っている、間違っている、だから非常に間違っている*、または* *頻繁にコミットする...これはあなたのために行う:あなたを遅くする、はい、そうだよ、遅くなる* –

+0

、私は今私の解決策に固執する良い議論を持っています。ありがとう。 – DoubleT28

+1

IIRC一部の膨大な更新プログラムでは、ロールバック・セグメント(「ORA-01555:スナップショットが古すぎます」)に関する問題があります。そのため、ブロック単位で更新することをお勧めします。 –

答えて

0

時間処理INSERTの多くを費やすプログラム、UPDATE、またはDELETE文、またはクエリの結果をループ。 DMLを発行するためのFORALL文、および問合せのBULK COLLECT INTOおよびRETURNING BULK COLLECT INTO句を調べる必要があります。この文書を目的に合わせてチェックすることができます。 http://docs.oracle.com/cd/B28359_01/appdev.111/b28370/tuning.htm

あなたの状況に応じてここに答えてください。

https://asktom.oracle.com/pls/asktom/f?p=100:11:0::NO::P11_QUESTION_ID:6407993912330

+0

'bulk collect'と' forall'は価値がありますが、通常はバッチ更新を行う方が良いです。一度にテーブル全体を更新することはできません。 – pohart

0

あなたのDBは、ダウンタイムを持っている場合は、最速のソリューションはTom Kyteが言うように行うには、おそらくです:

create table new as select ... from old; 
drop table old; 
rename table new to old; 

あなたはこの現象が発生することができ、ウィンドウを持っていない場合(それはおそらく注文です)テーブルをブロックすることができない場合は、dbms_parallel_executeをチェックアウトすることをお勧めします。 Oracleは表をチャンクに分割し、各チャンクを個別に更新できます。あなたが状態を確認行っていたら、あなただけの、あなたはその後、追加条件and rowid between :start and :stop

begin 
    dbms_parallel_execute.create_task (task_name => 'MyTask'); 
    dbms_parallel_execute.create_chunks_by_rowid(
     task_name => 'MyTask', 
     table_owner => 'Me', 
     table_name => 'MyTable', 
     by_row  => true, 
     chunk_size => 1000); 
    dbms_parallel_execute.run_task(
     task_name  => 'MyTask', 
     sql_stmt  => 'UPDATE mytable 
          set col = newval 
          where ... 
          and rowid between :start_id and :end_id', 
     language_flag => dbms_sql.native, 
     parallel_level => 8); 

と一つの大きな更新を望んでいた場合だろうupdateステートメントを使用することができますので、それはバルクの収集とFORALL更新するよりもずっときれいだ:

dbms_parallel_execute.task_status(task_name => 'MyTask') = dbms_parallel_execute.FINISHED 

タスクが成功した場合は削除します。

dbms_parallel_execute.drop_task(task_name => 'MyTask'); 
関連する問題