sql >> データベース >  >> RDS >> Oracle

Oracle DUP_VAL_ON_INDEX例外を無視することはどれほど悪いことですか?

    これはコーディングが最も簡単なので、通常はDUP_VAL_ON_INDEX例外を挿入してトラップします。これは、挿入する前に存在を確認するよりも効率的です。私たちが扱う例外はOracleによって発生するため、これを「悪臭」(恐ろしい言い回し!)とは見なしません。フロー制御メカニズムとして独自の例外を発生させるのとは異なります。

    Igorのコメントのおかげで、これに対して2つの異なるベンチアムクを実行しました。(1)最初の試みを除くすべての挿入試行が重複している場合、(2)すべての挿入が重複していない場合。現実は2つのケースの間のどこかにあります。

    注:Oracle10.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を選択する必要があるようです。



    1. mysqlデータを取得できません(CodeIgniter Selecting)

    2. 複合属性のインデックス

    3. 結合されたテーブルにLIMIT1を指定したMySQLJOIN

    4. 後でソートするために、phpからmysqlに日付を追加します