1

次のようなクエリがあります。

 delete from tableA 
 where tableA.fk in (select id 
                     from tableB 
                     where tableB.column1='somevalue' 
                     and tableB.date between date1 and date2)
   ;

テーブル tableB には、100,000,000 近くのレコードが含まれています。そう

select id 
from tableB 
where  tableB.column1='somevalue' 
and tableB.date between date1 and date2 

1,000,000 近くのレコードを返します。その結果、削除がまったく機能しません。ロールバック セグメントのサイズに問題があります。セグメントのサイズを大きくできません。

どのように実行できますか?

4

3 に答える 3

6

削除は、削除された行全体を保存する必要があるため、ロールバック(元に戻す)スペースの使用に関して最もコストのかかる操作です(一方、挿入ステートメントを元に戻すには、データベースにROWIDを保存する必要があります)。問題の最も簡単な解決策は、UNDO表領域にファイルを追加することです。

しかし、あなたは言う

「セグメントのサイズを大きくできません」

これは少し驚くべきことです。結局のところ、最近のディスクは安価です。恐らくあなたはあなたが近づくのが怖い怒っているDBAを持っていますか?しかし、DBAは、データベースを維持できるようにデータベースをプロビジョニングする義務を果たしていません。率直に言って、元に戻るスペースが不十分なVLDB(ペタバイトやゼタバイトの最近でも、1億行のテーブルがそのように数えられる)を持っているのはばかげています。

しかし、データセンターでミントタウルスを髭を生やさないのであれば、コードを変更するだけです。これが1つのオプションです。これを考えると...

select id 
from tableB 
where  tableB.column1='somevalue' 
and tableB.date between date1 and date2 

... 100万行を返すため、から削除しようとする行が多すぎるtableA場合は、より少ない行を返すサブクエリを試すことができます。演習の目的上、toで指定された範囲は30日であると想定していますdate1date2それに応じて、次のコードを調整する必要があります。

for i in 1..10 loop
    delete from tableA 
     where tableA.fk in (select id 
                         from tableB 
                         where tableB.column1='somevalue' 
                         and tableB.date between date1 + (3 * (i-1)) and  date1 + (3 * i)
       ;
    commit;
end loop

これにより、選択が10個の3日間のチャンクに分割されます。この方法でそれを行うにははるかに長い時間がかかりますが、Undoテーブルスペースを爆破するべきではありません。

于 2013-01-03T18:11:10.120 に答える
3

あなたがしたいことはこれです:

create table foo_bar  
as select  *  
from tableA   
where tableA.fk not in (select id from tableB where 
 tableB.column1='somevalue' and tableB.date between date1 and date2);  

元のテーブルの切り捨て + 削除が続く

truncate tableA  
drop tableA

次に、名前を変更foo_barしますtableA

alter table foo_bar  rename to tableA

すべてのインデックスを無効にしてください。

コメント

テーブルをドロップできません。それは常に使用されています。

あなたは間違いなくそうすることができます。view挿入中にデータを吹き飛ばすことができないため、単なる仮想関数であるの背後にテーブルを隠したり、メンテナンス時間を確保したりする必要があります。より一般的なアプローチは、このデータをmaterialized viewとして動作する にプッシュすることfact tableです。これにより、実体化されたビューに対するユーザー クエリを損なう心配なく、いつでもベース テーブル (tableA) を変更できます。

パラメータを使用すると、使用nologgingされるロールバックの量が減少します。で構築された具体化されたビューを回復することはできませんnologging

于 2013-01-03T17:04:29.307 に答える
2

ロールバックセグメントを埋めている場合は、トランザクションに関係するデータの量が原因である可能性があります。

私はいくつかのチャンクに分割し、それぞれをコミットします。

 delete from tableA where tableA.fk in (
    select id from (
            select id from tableB where 
                tableB.column1='somevalue' and tableB.date between date1 and date2 and id in (select distinct fk from tableA.fk)

        )
        where rownum < XXXX 
    )

XXXXに必要な値(10000)などを指定してから、このステートメントの実行をループし、各反復でコミットすることを忘れないでください。

deleteステートメントが0(影響を受ける行の数)を返すまでループする必要があります。

更新されたクエリ 気づいたように、これは最高のパフォーマンスを提供しませんが、ロールバックセグメントの問題を解決します

それが役に立てば幸い

于 2013-01-03T17:12:26.740 に答える