2012-03-20 11 views
0

私はoracle 9iで作業しています。私は約135,000,000のレコードを持つテーブルを持っています。 10,000,000行すべて索引付けされています。oracleで多数のデータを含むクエリを削除する

新しいビジネス要件として、これから約70,000,000行を削除する必要があります。

私は別のテーブルとして削除する行のバックアップを作成しました。

Table1 <col1, col2........> -- main table (135,000,000 rows) 

Table2 <col1, col2........> -- backup table (70,000,000 rows) 

下記の削除クエリを試行しました。

Delete from table1 t1 where exists (select 1 from table2 t2 where t2.col1 = t1.col1) 

ですが、無限の時間がかかります。

はその後も、まだ以上12時間稼動してい

declare 
cursor c1 is 
select col1 from table2; 
c2 c1%rowtype; 
cnt number; 
begin 
cnt :=0; 
open c1; 
loop 
    fetch c1 into c2; 
    exit when c1%notfound; 

    delete from table1 t1 where t1.col1 = c2.col1; 
    if cnt >= 100000 then 
     commit; 
    end if; 
    cnt:=cnt+1; 
end loop; 
close c1; 
end; 

を試してみました。まだ完了していません。

table1に複数のインデックスがあり、table2にcol1のインデックスがあることに注意してください。すべてのテーブルとインデックスが分析されます。

このシナリオに対して最適化の方法があるかどうかを教えてください。

ありがとうございます。

+0

あなたのコードが本当にそうであれば、100000行後のすべての行にコミットします。これはおそらくあなたが望むものではなく、遅くなります。 コミット後にあなたのcnt:= 0を設定してください –

+0

yaカウンターをリセットする必要があります。しかし、私はインデックスを削除し、トップの回答として再作成することをお勧めします。 –

答えて

4

ドロップすべてのインデックス(バックアップインクルードは、ステートメントを作成する) は、それからDELETEコマンドを作成 が、私は以前、この問題に直面して覚えているすべてのインデックス

4

を再作成し、バックアップテーブルを構築するために使用されるSELECT文を使用してください。あなたが残したいレコードを(

1)同一の構造

2と別のテーブルを作成します)新しいテーブルに挿入します。それは、他の削除操作よりも速く働いたので、その場合には、我々はこれを行うに頼っ私はバックアップに対してフィルタリングするために安価であると仮定すると、これを答えるつもりだ新しいテーブル

0

の名前を変更します)古いテーブルに

4ドロップ)

3)これをスピードアップするためのダイレクトパスインサートを使用テーブルが、それはwバックアップテーブルを作成するために使用した条件の否定を使うだけで安くなるでしょう。

1)同じ構造の新しいテーブルを作成します。インデックス、制約、トリガはありません。

必要なこれは、大量のを回避した場合

2)

 
    select 'insert /*+ append nologging */ into new_table partition (' || n.partition_name || ') select * from old_table partition (' || o.partition_name || ') minus select * from bak_table partition (' || b.partition_name || ');' 
    from all_tab_partitions o, all_tab_partitions n, all_tab_partitions b 
    where o.partition_no = all(n.partition_no, b.partition_no) 
     and o.table_name = 'OLD_TABLE' and o.table_owner = 'OWNER' 
     and n.table_name = 'NEW_TABLE' and n.table_owner = 'OWNER' 
     and b.table_name = 'BAK_TABLE' and b.table_owner = 'OWNER'; 
    -- note, I haven't run this it may need minor corrections in addition to the obvious substitutions 

3)以前のクエリ

4)インデックス、制約を構築した結果を検証し、実行、およびトリガ削除と比較してやり直しと元に戻す。ダイレクトパスの APPENDヒントが さらにREDOを減らすために何のロギングを挿入していない - ことを確認してくださいバックアップはその後 は

おそらく並列で速く行くことが少ないパスでソートすることができチャンクに仕事を破るために、あなたのパーティショニングを利用しています挿入+並列選択が必要ですが、おそらく必要ありません。挿入せずにパラレル選択を行わないでください。 "alter session enable parallel dml"

+0

'nologging'は本当のヒントではなく、' append'だけが必要です。 –

1

テーブルが分割されているとします。特定のパーティション内のすべてのデータを削除するつもりですか?その場合は、ドロップしたい7000万行のパーティションが7つだけドロップされるようにする必要があります。私はあなたの問題はそれほど簡単ではないと仮定しています。

あなたがトランザクションの一貫性を気にしないことを意味暫定コミットをして、行うことができれば、最も効率的なアプローチは、それがなければ、のではなく、バックアップのテーブルを作成する

CREATE TABLE rows_to_save 
    AS SELECT * 
     FROM table1 
     WHERE <<criteria to select the 65 million rows you want to keep>> 

TRUNCATE TABLE table1; 

INSERT /*+ append */ 
    INTO table1 
SELECT * 
    FROM rows_to_save; 

の線に沿って何かありそうです、単にあなたはまた、落としたりDELETEを実行する前に、インデックスと制約を無効から利益を得ることができるDELETE声明

DELETE FROM table1 
WHERE <<criteria to select the 70 million rows you want to keep>> 

を発行する方が効率的でしょう。

関連する問題