1

私はこの声明を持っています:

update new_table t2
set t2.creation_date_utc =
(select creation_date from old_table t1 where t2.id = t1.id)
where exists
(select 1 from old_table t1 where t2.id = t1.id);

説明計画によると、コストは 150959919 です。説明計画では、合計コストが 3000 程度の完全なテーブル アクセスが示され、更新には基本的に無限のコストがかかります。実行すると、実際に永遠に続くようです。

参考までに、これらのテーブルにはそれぞれ 30 万行以下しかありません。

さらに、このクエリ。

select 
(select creation_date from old_table t1 where t2.id = t1.id)
from new_table t2;

基本的に即日終了。

これの原因は何ですか?

4

4 に答える 4

3

あなたが言及した形式の更新ステートメントがある場合、それはidフィールドがold_table全体で一意であることを意味します(そうでない場合、最初の内部クエリは、実際には1つの値しか処理できないのに、更新のために複数の値を返すエラーを発生させます)。したがって、最初のクエリを次のように変更できます(冗長であるため、where 句を削除します):-

update new_table t2
set t2.creation_date_utc =
(select creation_date from old_table t1 where t2.id = t1.id);

テーブル全体のスキャンが原因で、上記のクエリにまだ時間がかかる可能性があります。したがって、2 つのオプションがあります。

  1. 次のコマンドを使用して、id フィールドの old_table テーブルにインデックスを適用します。

    Create index index_name on old_table(id);
    
  2. 更新クエリを次のように変更します (未テスト):-

    update new_table t2
    set t2.creation_date_utc=
    (select creation_date from old_table t1 where t2.id=t1.id and rownum=1);
    

rownum=1 は、old_table で最初の一致が見つかるとすぐにそれ以上検索を行わないようにオラクルに指示する必要があります。

ただし、最初のアプローチをお勧めします。

于 2013-01-29T02:36:52.967 に答える
2

old_table.idにインデックスがなく、ネストされたループ結合は非常にコストがかかります。old_table(id、creation_date)のインデックスが最適です。

于 2013-01-29T00:18:22.533 に答える
1

なぜマージステートメントを使用しないのですか? 同様のケースでは、より効率的であることがわかりました。

merge into new_table t2
using old_table t1 
on (t2.id = t1.id)
when matched then
    update set t2.creation_date_utc = t1.creation_date;
于 2013-01-29T09:46:38.610 に答える
0

これはより高速で同等かもしれません:

update new_table t2
set t2.creation_date_utc =
(select creation_date from old_table t1 where t2.id = t1.id)
where t2.id in
(select id from old_table t1);
于 2013-01-29T00:59:57.880 に答える