すべての行を更新


12

単一の列の非常に大きなOracleテーブルのすべての行を更新する最も効率的な方法を知りたいです。例えば:

update mytable set mycolumn=null;

または:

update mytable set mycolumn=42;

私の知識は非常に古いかもしれません。テーブルを変更して列を削除します。次に、テーブルを変更して、使用する新しい値のデフォルト値を持つ列を追加します。次に、テーブルを変更して、列のデフォルト値を削除します。これは更新を実行するよりもはるかに高速であることがわかりましたが、より良い方法があると感じています。


私が理解している限り、デフォルトで新しい非NULL列を追加することは、Oracleでのメタデータのみの変更です。「すべての行を同じ値に更新する」ケースを最適化したとは思えません。これはあなたにとって一般的な操作ですか?
マーティンスミス

1
両方の方法を試して、時間を計ってください。あなたがこれを行うのを妨げているのは何ですか?異なる結果ではなく、同じ結果で終了しなければならないという事実を見てください!それ以外の場合、比較は無効です。
tvCa

@tvCa私は両方の方法を試しました。更新するだけで約2時間実行された後、強制終了します。列をドロップすると、数秒しかかかりません。デフォルト値なしで列を追加する(列を無効にする)のに数秒しかかかりません。デフォルト値で列を追加するには、約30分かかります。そのため、たとえば、列のすべての値を 'Some Value'に設定する場合、現在、列をドロップして追加します。それを行うより速い方法があるかどうかを知りたいだけです。
カイノー

2
11gR2を使用していますか?@MartinSmithは正しいです。NOT NULLとしてDEFAULTを使用して新しい列を追加する方法は、NULLとして追加するよりもはるかに速い変更であるため、テーブル内のすべての行を強制的に更新する(UPDATEステートメントの発行と同様)方法については、こちら参照してください。DEFAULTをディクショナリに格納することでパフォーマンスが向上するため、後でDEFAULT値を削除するという問題が発生します。また、その時点でNOT NULL制約を処理する必要があります。
-ansible

回答:


2

この一括更新を行っている間、このテーブルに対して行われている他のアクティビティに大きく依存します。あなたがしたいことのサンプルをいくつか実行して、どの方法が最適であるかのアイデアを得ることができる、ある種のテスト環境があることを願っています。私が試してみます:

  1. シングルを実行しupdate table set column_name = blahます;
  2. plSqlループを作成して、テーブル内のすべての主キーを選択してループし、すべてのupdating the column=blahX更新(おそらく10000)をコミットします。このコードをコピーして、プライマリキーの別のセクションにコピーさせることにより、このコードを並列化できます。

OLTPシステムで非常にアクティブに使用されているテーブルで非常によく似た問題があり、5倍に並列化でき、10000ごとにコミットする100以上のMM行テーブルでユーザーロックの影響なしで実行できました。テーブルが大きいか、実行しているアプリケーションの種類が異なりますが、この種のソリューションが適している場合があります。


0

高速の場合、UPDATE起動しているトリガーがないことを確認してください。

SELECT trigger_name, status FROM user_triggers WHERE table_name = 'MYTABLE';

ALTER TABLE mytable DISABLE ALL TRIGGERS;

完了したら、必要なものだけを再度有効にしてください。

ALTER TRIGGER mytrigger ENABLE;

また、インデックスメンテナンスのオーバーヘッドが発生する場合があります。インデックスを個別に再構築してください。これを行うには、pappesによるここの答えが役立つはずです:https ://stackoverflow.com/questions/129046/disable-and-later-enable-all-table-indexes-in-oracle

参考のために、ここでpappesの回答を繰り返します。(このSPOOLコマンドは、プラットフォームと環境に関する仮定を行うことに注意してください。)

set pagesize 0    
alter session set skip_unusable_indexes = true;
spool c:\temp\disable_indexes.sql
select 'alter index ' || u.index_name || ' unusable;' from user_indexes u;
spool off
@c:\temp\disable_indexes.sql

インポートする...

select 'alter index ' || u.index_name || ' rebuild online;'
  from user_indexes u;

-1

インデックスを削除します。列を更新します。インデックスを返します。ただし、列のすべての行に同じ値が含まれている場合は、インデックスを削除できます。


-2

スペースに制限がない場合は、テーブルに新しい列を追加したテーブルと同じ新しいテーブルを作成し、古いテーブルを削除できます。

create new_table as
select old_table.*, (with or without default_Value) as new_column
from old_table;

1
これはより効率的ですか?どうして?また、既存のテーブルを参照するFKがある場合はどうなりますか?
ypercubeᵀᴹ

はい、他のサンプルテーブルで試して、自分で結果を確認できます。FKがある場合、正確にはわかりませんが、効率的な場合は無効にして有効にすることができます。
E_Salamon

-3

複数の更新/コミットシーケンスを試してください。コミットせずに行を挿入/更新/削除しすぎると、IOの負荷が高くなります。ブロックサイズやレコードサイズなどを知って、かなり最適化できます。

テーブルのデータ全体を削除するにtruncate table xは、の方が優れていdelete from xます。また、パージによって別のプロセスのワークロードが発生します。

編集:inmemoryオプションを使用して、表を列形式でメモリにロードしてから更新を実行できます。DBの関係と構造に本当に依存します。こちらの記事をご覧ください


3
テーブルの1列を更新したい。私はどのように表示されていないtruncateか、delete任意の助けになるでしょう。
ypercubeᵀᴹ

@ypercubeコミットせずに複数のデータを操作すると、望ましくないIO負荷がどのように生じるかを説明しました。更新または他のOLTPのいずれかです。
unningな

3
コミットを頻繁に行うとI / O がどの程度減少するか説明できますか チェックポイントが原因でI / O が増加しませんか?
ムスタッチョ

3
従来とは異なる用語(「txジャーナル」、「セッションのフラッシュ」)の使用は少しわかりにくいです。複数の短いトランザクションを使用する場合でも、1つの大規模なトランザクションを使用する場合でも、生成されるREDOレコードの合計量は同じになります。I / O操作は、REDOログバッファーがディスクに書き込まれたとき(バッファーキャッシュチェックポイントだけを残す)にのみ発生します。これは、コミット時またはREDOバッファーがほぼいっぱいになったときに発生します。その後、頻繁にコミットすると、追加のI / Oが発生するため、 I / Oをどのように削減できるのか疑問に思っています。
mustaccio

4
あなたはトム・カイトが「頻繁にコミット」について言いたいこと参照することもできます。asktom.oracle.com/pls/apex/...間違っている、間違っている、間違っているので、間違った....だから、非常に非常に間違っています。
a_horse_with_no_name
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.