3

いくつかのシナリオがあります。

  1. 事前定義された順序で3つの異なるテーブルから列の値を読み取る必要があり、1つのテーブルのみがデータを保持します

  2. 指定された基準のレコードが存在する場合はtable1からデータを読み取り、指定された基準のTable2からデータを読み取ります

Oracleストアドプロシージャの場合

これらが現在処理されている方法は、最初に特定のクエリのカウントを変数に取得することです。カウントが0より大きい場合は、次のように同じクエリを実行して実際のデータを読み取ります。

select count(*) from table1 into v_count
if v_count > 0
then
    select data into v_data from table1
end if;

Return v_data

これは、no_data_found例外を回避するために行われています。そうしないと、テーブルアクセスごとにno_data_found例外をキャッチするために3つの例外ハンドラブロックが必要になります。

現在、カーソルを使用してこれを再実装しているので、次のようになります。

cursor C1 is
    select data from table1;
Open C1
Fetch C1 into v_data
if C1%FOUND
then
    Close C1
    Return v_data
End If

パフォーマンスの観点からどちらが優れているかを知りたいと思いました。カーソルを使用するものと、変数に対してSelectを実行し、3つのno_data_foundExceptionブロックを使用するものです。現在の2段階のクエリプロセスは使いたくありません。

4

6 に答える 6

5

なぜあなたが例外を避けたいと思っているのかわかりませんか?何が問題なのですか:

begin
    begin
        select data into v_data from table1;
    exception
        when no_data_found then
        begin
            select data into v_data from table2;
        exception
            when no_data_found then
            begin
               select data into v_data from table3;
            exception
                when no_data_found then
                    v_data := null;
            end;
        end;
    end;
    return v_data;
end;

これは、目的の結果を達成するために最小限の作業を行うため、他のソリューションよりも優れたパフォーマンスを発揮すると思います。

Oracle DUP_VAL_ON_INDEX 例外を無視するのはどれほど悪いことですか?を参照してください。ここで、データがあるかどうかを確認するためにカウントするよりも、例外を使用する方がパフォーマンスが優れていることを示しています。

于 2009-04-29T13:24:32.443 に答える
4
select count(*) from table1 into v_count
if v_count > 0 then
    select data into v_data from table1;
else
    v_data := null;
end if;
return v_data;

と同等ではありません

begin
    select data into v_data from table1;
    return v_data;
exception
    when no_data_found then
        return null;
end;

マルチユーザー環境で。最初のケースでは、存在を確認する時点とデータを読み取る時点の間に、誰かがテーブルを更新する可能性があります。

パフォーマンスに関しては、どちらが優れているかわかりませんが、最初のオプションでは SQL エンジンに対して 2 つのコンテキスト スイッチが行われ、2 つ目のオプションでは 1 つのコンテキスト スイッチしか行われないことがわかっています。

于 2009-04-29T11:15:11.660 に答える
1

「DaveCosta」のMINオプションの拡張バージョン...

SELECT COUNT(1), MIN(data) INTO v_rowcount, v_data FROM table2;

これで、通常の選択クエリがスローまたは例外v_rowcountをスローする値0、> 1(1より大きい)をチェックできます。値「1」は、正確に1つの行が存在し、目的を果たすことを示します。NO_DATA_FOUNDTOO_MANY_ROWS

于 2011-03-10T07:45:40.807 に答える
1
DECLARE
    A VARCHAR(35);
    B VARCHAR(35);
BEGIN
    WITH t AS
    (SELECT OM_MARCA, MAGAZIA FROM ifsapp.AKER_EFECTE_STOC WHERE (BARCODE = 1000000491009))
    SELECT
    (SELECT OM_MARCA FROM t) OM_MARCA,
    (SELECT MAGAZIA FROM t) MAGAZIA
    INTO A, B
    FROM DUAL;
    IF A IS NULL THEN
       dbms_output.put_line('A este null');
    END IF;
    dbms_output.put_line(A);
    dbms_output.put_line(B);
END;
/
于 2010-01-27T17:14:28.303 に答える
1

シナリオ 1 の処理方法は良くありません。1 つのクエリで十分な場合に 2 つのクエリを実行するだけでなく、Erik が指摘したように、2 つのクエリ間でデータが変更される可能性が生じます (読み取り専用またはシリアル化可能なトランザクションを使用しない限り)。

この場合、データは 3 つのテーブルのうちの 1 つに正確に収まるとおっしゃっていますが、これはどうでしょうか。

SELECT data
  INTO v_data FROM
  (SELECT data FROM table1
   UNION ALL
   SELECT data FROM table2
   UNION ALL
   SELECT data FROM table3
  )

複数のデータが見つからないハンドラーを作成しないようにするために使用できる別の「トリック」は次のとおりです。

SELECT MIN(data) INTO v_data FROM table1;
IF v_data IS NOT NULL THEN
   return v_data;
END IF;

SELECT MIN(data) INTO v_data FROM table2;
...etc...

しかし、例外ハンドラを 3 つ持つよりも優れている理由はまったくわかりません。

2 番目のシナリオでは、両方のテーブルにデータが存在する可能性があり、存在する場合は table1 のデータを使用し、そうでない場合はテーブル 2 のデータを使用したいということだと思います。これも 1 つのクエリで実行できます。

SELECT data
  INTO v_data FROM
  (SELECT data FROM
    (SELECT 1 sort_key, data FROM table1
     UNION ALL
     SELECT 2 sort_key, data FROM table2
    )
   ORDER BY sort_key ASC
  )
  WHERE ROWNUM = 1
于 2009-04-29T12:45:33.270 に答える
0

ループの「forrowincursor」形式を使用すると、データがない場合、ループは処理されません。

declare cursor
t1Cur is
 select ... from table1;
t2Cur is
 select ... from table2;
t3Cur is
 select ... from table3;
t1Flag boolean FALSE;
t2Flag boolean FALSE;
t3Flag boolean FALSE;
begin
for t1Row in t1Cur loop
  ... processing, set t1Flag = TRUE
end loop;
for t2Row in t2Cur loop
  ... processing, set t2Flag = TRUE
end loop;
for t3Row in t3Cur loop
  ... processing, set t3Flag = TRUE
end loop;
... conditional processing based on flags
end;
于 2009-04-29T12:00:48.820 に答える