これはコーディングが最も簡単なので、通常は DUP_VAL_ON_INDEX 例外を挿入してトラップするだけです。これは、挿入前に存在をチェックするよりも効率的です。私たちが処理する例外は Oracle によって生成されるため、これを「悪臭」(ひどい言い回し!) とは考えていません。これは、フロー制御メカニズムとして独自の例外を生成するようなものではありません。
Igor のコメントのおかげで、これについて 2 つの異なるベンチマークを実行しました: (1) 最初の試行を除くすべての挿入試行が重複している場合、(2) すべての挿入が重複していない場合。現実は、2 つのケースの間のどこかにあるでしょう。
注: テストは Oracle 10.2.0.3.0 で実行されました。
ケース 1: ほとんどが重複
最も効率的なアプローチは(重要な要因による)、挿入中に存在を確認することです。
prompt 1) Check DUP_VAL_ON_INDEX
begin
for i in 1..1000 loop
begin
insert into hasviewed values(7782,20);
exception
when dup_val_on_index then
null;
end;
end loop
rollback;
end;
/
prompt 2) Test if row exists before inserting
declare
dummy integer;
begin
for i in 1..1000 loop
select count(*) into dummy
from hasviewed
where objectid=7782 and userid=20;
if dummy = 0 then
insert into hasviewed values(7782,20);
end if;
end loop;
rollback;
end;
/
prompt 3) Test if row exists while inserting
begin
for i in 1..1000 loop
insert into hasviewed
select 7782,20 from dual
where not exists (select null
from hasviewed
where objectid=7782 and userid=20);
end loop;
rollback;
end;
/
結果 (解析のオーバーヘッドを避けるために 1 回実行した後):
1) Check DUP_VAL_ON_INDEX
PL/SQL procedure successfully completed.
Elapsed: 00:00:00.54
2) Test if row exists before inserting
PL/SQL procedure successfully completed.
Elapsed: 00:00:00.59
3) Test if row exists while inserting
PL/SQL procedure successfully completed.
Elapsed: 00:00:00.20
ケース 2: 重複なし
prompt 1) Check DUP_VAL_ON_INDEX
begin
for i in 1..1000 loop
begin
insert into hasviewed values(7782,i);
exception
when dup_val_on_index then
null;
end;
end loop
rollback;
end;
/
prompt 2) Test if row exists before inserting
declare
dummy integer;
begin
for i in 1..1000 loop
select count(*) into dummy
from hasviewed
where objectid=7782 and userid=i;
if dummy = 0 then
insert into hasviewed values(7782,i);
end if;
end loop;
rollback;
end;
/
prompt 3) Test if row exists while inserting
begin
for i in 1..1000 loop
insert into hasviewed
select 7782,i from dual
where not exists (select null
from hasviewed
where objectid=7782 and userid=i);
end loop;
rollback;
end;
/
結果:
1) Check DUP_VAL_ON_INDEX
PL/SQL procedure successfully completed.
Elapsed: 00:00:00.15
2) Test if row exists before inserting
PL/SQL procedure successfully completed.
Elapsed: 00:00:00.76
3) Test if row exists while inserting
PL/SQL procedure successfully completed.
Elapsed: 00:00:00.71
この場合、DUP_VAL_ON_INDEX が 1 マイルも勝ちます。どちらの場合も、「挿入前に選択」が最も遅いことに注意してください。
したがって、挿入が重複しているかどうかの相対的な可能性に応じて、オプション 1 または 3 を選択する必要があるようです。