通常のループの代わりに明示的なカーソルを使用するのはなぜですか?


12

私は1年間(Oracle dbの場合)基本的なWebアプリを作成してきましたが、関数はかなりシンプルなので、ほとんどの人は通常のFORループを使用してデータを取得します。

for i in (select * from STUDENTS) loop
      htp.prn(i.student_last_name || ', ' || i.student_first_name || ' ' || i.student_dob);
end loop;

しかし、カーソルは物事を行う「正しい」方法のようです。カーソルとは何か、さまざまな方法でループする方法については多くの情報を見つけることができますが、通常のFORループでそれらを使用する理由はわかりません。手順の必要性に依存していますか?知っておくべき固有の利点はありますか?


このタイプは、FORカーソルを使用するもう1つの方法です。次のドキュメントを参照してください:docs.oracle.com/cd/E11882_01/appdev.112/e10472/… とにかく、htp.prn()は何をしますか?
dezso 2012年

これは、出力関数の1つです。では、どの方法を使用するかについて好みはありますか?
ini

この種のものについては、FORループがはるかに読みやすいと思います。「実際の」カーソルを使用する傾向があるのは、単に順方向ではなく、逆方向に進む必要がある場合のみです。の代わりにテーブル関数を想像できるため、他の質問をしましたhtp.prn()
dezso 2012年

カーソルの両方の形式は、純粋なSQLソリューションよりもパフォーマンスが劣ることに言及する価値があります。特にDMLステートメントに関連しています。
David Aldridge

回答:


7

カーソルは明示的または暗黙的にすることができ、どちらのタイプもFORループで使用できます。質問には2つの側面があります。

  1. 暗黙的なカーソルFORループではなく明示的なカーソルFORループを使用する理由

    • クエリを再利用する場合は、明示的なカーソルのFORループを使用します。そうでない場合は、暗黙のカーソルが優先されます。
  2. 明示的なFETCHのないFORループではなく、FETCHを使用したループを使用するのはなぜですか?

    • 一括収集が必要な場合、または動的SQLが必要な場合は、ループ内でFETCHを使用します。

ドキュメントから役立つ情報をいくつか紹介します。

LOOPの暗黙カーソルの例

BEGIN
   FOR vItems IN (
      SELECT last_name
      FROM employees
      WHERE manager_id > 120
      ORDER BY last_name
   ) 
   LOOP
      DBMS_OUTPUT.PUT_LINE ('Name = ' || vItems.last_name);
   END LOOP;
END;
/

LOOPの明示的なカーソルの例

DECLARE
   CURSOR c1 IS
      SELECT last_name
      FROM employees
      WHERE manager_id > 120
      ORDER BY last_name;
BEGIN
   FOR vItems IN c1 LOOP
      DBMS_OUTPUT.PUT_LINE ('Name = ' || vItems.last_name);
   END LOOP;
END;
/

暗黙カーソル

暗黙カーソルは、PL / SQLによって構築および管理されるセッションカーソルです。PL / SQLは、SELECTまたはDMLステートメントを実行するたびに暗黙カーソルを開きます。暗黙カーソルを制御することはできませんが、その属性から情報を取得できます。

暗黙的なカーソルは、関連するステートメントが実行された後に閉じます。ただし、その属性値は、別のSELECTまたはDMLステートメントが実行されるまで利用可能です。

暗黙的なカーソル属性は、SQL%ISOPEN、SQL%FOUND、SQL%NOTFOUND、SQL%ROWCOUNT、SQL%BULK_ROWCOUNT、SQL%BULK_EXCEPTIONSです。

明示的なカーソル

明示カーソルは、ユーザーが作成および管理するセッションカーソルです。明示的なカーソルを宣言して定義し、名前を付けてクエリに関連付ける必要があります(通常、クエリは複数の行を返します)。次に、次のいずれかの方法でクエリ結果セットを処理できます。

(OPENステートメントを使用して)明示的なカーソルを開き、(FETCHステートメントを使用して)結果セットから行をフェッチし、(CLOSEステートメントを使用して)明示的なカーソルを閉じます。

カーソルFOR LOOPステートメントで明示的なカーソルを使用します(「カーソルFOR LOOPステートメントを使用したクエリ結果セット処理」を参照)。

明示的なカーソルに値を割り当てたり、式で使用したり、仮のサブプログラムパラメータまたはホスト変数として使用したりすることはできません。カーソル変数を使用してこれらのことを実行できます(「カーソル変数」を参照)。

暗黙カーソルとは異なり、明示カーソルまたはカーソル変数をその名前で参照できます。したがって、明示的なカーソルまたはカーソル変数は、名前付きカーソルと呼ばれます。

カーソルFOR LOOPステートメント

カーソルのFOR LOOPステートメントを使用すると、SELECTステートメントを実行し、結果セットの行をすぐにループできます。このステートメントでは、暗黙的または明示的なカーソルを使用できます。


1
暗黙カーソルは、10g以降、一度に100行をフェッチします。
David Aldridge

16

投稿したコードはカーソルを使用しています。暗黙のカーソルループを使用しています。

明示的なカーソルループを使用する(つまり、宣言セクションでCURSOR変数を宣言する)と、コードが簡潔になるか、パフォーマンスが向上する場合があります。

  1. ビューにリファクタリングできない複雑なクエリがある場合、ループが繰り返されるとコードが読みやすくなります。 student_cursor一連のロジックを埋め込む30行のSQLステートメントを含めるのではなく。たとえば、卒業することを許可され、学業成績のあるテーブルへの参加を含むすべての学生、学位プログラムの要件、学籍情報に関するテーブル、期限切れの図書館の本に関する情報を持つテーブルを印刷した場合、未払い料金、管理オーバーライドなどに関する情報を含むテーブル。コードをリファクタリングして、このクエリがユーザーへのリストの表示に関連するコードの途中で動かなくなることがないようにするのはおそらく妥当でしょう。これには、このすべてのロジックをカプセル化するビューの作成が含まれる場合があります。または、現在のPL / SQLブロックの一部として、またはいくつかのより高レベルのPL / SQLブロック(つまり、カーソルがパッケージで宣言されているため)、再利用可能です。または、カプセル化と再利用のために何か他のことを行う必要があるかもしれません(たとえば、代わりにパイプラインテーブル関数を作成する)。
  2. PL / SQLで一括操作を利用する場合は、通常、明示的なカーソルを使用します。以下は、明示的カーソルと暗黙的カーソルのパフォーマンスの違いを説明するStackOverflowスレッドです。あなたがしているすべてがを呼び出すことである場合htp.prnBULK COLLECTおそらくあなたが何かを購入することはありません。ただし、他の場合では、パフォーマンスが大幅に向上する可能性があります。

2

多くの開発者が古い習慣から暗黙のカーソルではなく明示的なカーソルを使用していることがわかります。これは、Oracleバージョン7に戻ると、これが常により効率的な方法であったためです。今日では一般的に逆の方法があります。特にオプティマイザを使用すると、必要に応じてループの暗黙カーソルを一括収集に書き換えることができます。


0

最近、暗黙のFORループからの一連のクエリを明示的なカーソルに書き換える必要がありました。その理由は、クエリがリンクを介して外部データベースからデータをフェッチし、このデータベースがローカルデータベースとは異なるエンコーディングを使用していたためです。暗黙カーソルからローカルに定義されたレコードタイプにデータを転送すると、不思議な断続的なエラーが発生しました(特定の特定の行でのみ)。私たちのDBAはこれを私たちに説明しました、私たちはこれの底に到達することができなかっただろう。これは報告されているOracleのバグのようです。

明示的なカーソルを使用してすべてを書き直すことをお勧めし、エラーはなくなりました。

暗黙的ではなく明示的に使用する主な理由ではありませんが、注意する価値があります。

編集:Oracle 12c。


バグやメモ番号を追加して、これを読んだ人が症状について、またこれが解決されたかどうか、いつ解決できるかを知ることができますか?
リーリフェル2016年

申し訳ありませんが、バグの報告は私たちのDBAの1人が行ったものです。私はその情報にアクセスできません。
Robotron
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.