web-dev-qa-db-ja.com

PL / SQLでCURSORをループするためのFETCH / FORの違い

カーソルをフェッチすると、%ROWCOUNT、%ROWTYPE、%FOUND、%NOTFOUND、%ISOPENなどの変数にアクセスできることを知っています

...しかし、他に使用する理由があるかどうか疑問に思っていました

開く-フェッチ-カーソルをループする指示を閉じる

のではなく

カーソルをFORサイクルでループします...(私の意見では、これは単純なのでより良いです)

どう思いますか?

14
Jimmy

パフォーマンスの観点から見ると、この違いは OMGポニーがリンクしているティムホールのヒント よりもはるかに複雑です。このヒントは、Web用に抜粋されたより大きなセクションの紹介であると思います。ティムは、本のこれらのポイントのすべてではないにしても、ほとんどのポイントを占めることを期待しています。また、この説明全体は、使用しているOracleのバージョンによって異なります。これは10.2、11.1、および11.2については正しいと思いますが、古いリリースに戻って始めると、明らかに違いがあります。

先端の特定の例は、まず第一に、かなり非現実的です。 SELECT INTOではなく明示的なカーソルを使用して単一行フェッチをコーディングする人を見たことがありません。したがって、SELECT INTOの方がより効率的であるという事実は、実用上の重要性が非常に限られています。ループについて説明している場合、関心のあるパフォーマンスは、多くの行をフェッチすることのコストです。そして、そこから複雑さが入り始めます。

Oracleは10.1で、カーソルからPL/SQLコレクションにデータのBULK COLLECTを実行する機能を導入しました。これは、一度に多くの行をフェッチすることでコンテキストのシフトを最小限に抑えることができるため、SQLエンジンからPL/SQLコレクションにデータを取得するためのはるかに効率的な方法です。また、コードがPL/SQLエンジン内にとどまることができるため、これらのコレクションに対する後続の操作はより効率的です。

ただし、BULK COLLECT構文を最大限に活用するには、通常、明示的なカーソルを使用する必要があります。これにより、PL/SQLコレクションにデータを入力してから、FORALL構文を使用してデータベースにデータを書き戻すことができます(カーソルで大量のデータをフェッチする場合は、何らかの操作を行って、操作したデータをどこかに保存している可能性が高いと考えられます。 FORループで暗黙カーソルを使用する場合、OMGポニーが正しく指摘するように、OracleはバックグラウンドでBULK COLLECTを実行して、データのフェッチをより安価にします。ただし、データがコレクション内にないため、コードでは行ごとの挿入と更新が遅くなります。明示カーソルは、LIMITを明示的に設定する機会も提供します。これにより、FORループの暗黙カーソルのデフォルトの100よりもパフォーマンスが向上します。

一般に、10.2以降を使用していて、コードがデータをフェッチしてデータベースに書き戻すと仮定すると、

最速

  1. (適切なLIMITを使用して)ローカルコレクションにBULK COLLECTを実行し、FORALLを使用してデータベースに書き戻す明示的なカーソル。
  2. 暗黙的なカーソルがバックグラウンドでBULK COLLECTを実行し、datbaseに1行の書き込みを返します。
  3. BULK COLLECTを実行せず、PL/SQLコレクションを利用しない明示的なカーソル。

最も遅い

一方、暗黙のカーソルを使用すると、古いコードのリファクタリングや新機能の学習にかかる初期費用がほとんどなく、一括操作を使用できるという大きなメリットがあります。 PL/SQLの開発のほとんどが、主要言語が他の言語であるか、必ずしも新しい言語機能に追いついていない開発者によって行われている場合、FORループは、すべてを使用する明示的なカーソルコードよりも理解と維持が容易になります。新しいBULK COLLECT機能。 Oracleが将来新しい最適化を導入するとき、明示的なコードが手動での手直しを必要とする可能性がある一方で、暗黙のカーソルコードが自動的にメリットを得る可能性がはるかに高くなります。

もちろん、ループコードのさまざまなバリアントがどれほど高速であるかを本当に気にするまで、パフォーマンスのトラブルシューティングを行っているときには、多くの場合、より多くのロジックを純粋なSQLに移行することを検討する必要があります。ループするコードを完全に捨てます。

27
Justin Cave

OPEN/FETCH/CLOSEは、明示的カーソル構文と呼ばれます。後者は暗黙カーソル構文と呼ばれます。

すでに気付いた主な違いの1つは、暗黙カーソルでは%FOUND /%NOTFOUND/etcを使用できないことです...もう1つ注意すべき点は、暗黙カーソルは明示カーソルよりも高速であることです。先読み(〜 100レコードですか?)明示的なロジックをサポートしていません。

追加情報:

7
OMG Ponies

私が間違っている場合は修正してください。ただし、どちらにも他の機能にはない素晴らしい機能があると思います。

Forループを使用すると、次のようにすることができます。

for i in (select * from dual)
  dbms_output.put_line('ffffuuu');
end loop;

そして、open .. fetchを使用すると、次のように実行できます。

declare
  cur sys_refcursor;
  tmp dual.dummy%type;
begin
  open cur for 'select dummy from dual';
  loop
    fetch cur into tmp;
    exit when cur%notfound;
    dbms_output.put_line('ffffuuu');
  end loop;
  close cur;
end;

したがって、オープンフェッチでは動的カーソルを使用できますが、forループでは宣言なしで通常のカーソルを定義できます。

3
Jokke Heikkilä

この2つの実現の重要な違いについては、1つ以外はわかりません。for ... loopは、ループの終了後に暗黙的にカーソルを閉じます。open ... fetch ... close構文の場合、カーソルを自分で閉じます(ちょうど方法)-これは必要ではないと考えました:Oracleはカーソルを自動的に表示範囲から外に閉じます。また、%FOUNDカーソルで%NOTFOUNDおよびfor ... loopを使用することはできません。

私については、for ... loopの実現が非常に読みやすく、サポートしやすいと思います。

3
andr