web-dev-qa-db-ja.com

データベースカーソルを使用する利点は何ですか?

それは私が直面したインタビューの質問に基づいています。

非常に短い定義は

クエリによって返される行を操作するために使用できます。

カーソルの使用に加えて(ポイントは here MSDNにリストされています)、クエリまたはストアドプロシージャを使用してすべての操作を実行できる場合(私が間違っていなければ、 Transact-SQL for ms-sqlを使用できるように)、カーソルを使用する必要がある具体的なポイントはありますか?

41
Vikas

大きな結果セットと比較してカーソルを使用することは、一気にビデオをダウンロードし、ダウンロード後に見るのではなく、ビデオストリーミングを使用するようなものです。ダウンロードする場合、ダウンロードが終了するまで待機するためのスペースと忍耐が必要です。これで、マシンやネットワークがどれほど高速であっても、誰もが同じ速度で映画を見ることができます。

通常、クエリはサーバーに送信されて実行され、結果セットがネットワーク経由で1回のバーストで送信されます。カーソルを使用すると、行ごとにデータにアクセスでき、要求した場合にのみすべての行をストリーミングできます(実際に表示できます)。

  • カーソルを使用すると時間を節約できます-完全なレコードセットの処理とダウンロードを待つ必要がないため
  • サーバーとクライアントの両方で、結果セットに大きなメモリを割り当てる必要がないため、メモリを節約できます。
  • ネットワークとサーバーの両方の負荷分散-通常、「バースト」モードでの作業はより効率的ですが、サーバーとネットワークを完全にブロックできます。このような遅延は、マルチユーザー環境ではあまり望ましくありません。ストリーミングには、他の操作の余地があります。
  • カーソルに直接影響しないクエリ対象テーブル(特定の条件下)での操作を許可します。そのため、カーソルを行に保持している間、他のプロセスは他の行の読み取り、更新、さらには削除を行うことができます。これは、特に非常に忙しいテーブル、多くの同時読み取りと書き込みに役立ちます。

ただし、次の点に注意してください。

  • 一貫性:カーソルを使用して、データの一貫したスナップショットではなく(通常)操作します。したがって、同時実行/一貫性/分離は、データベース全体(ACID)から1行のみに保証されます。通常、DBMSにどのレベルの同時実行性を要求するかを通知できますが、細心の注意(現在のテーブル全体をロックしている)である場合、サーバー側のリソース節約の多くを破棄します。

  • すべてのパケットを送信することは非常に効率が悪い場合があります。すべてのパケットにはネゴシエーションのオーバーヘッドがあり、パケットごとに圧縮された大きなデータチャンクを送信することで回避できるためです。 (すべての行を個別に送信するのに十分なDBサーバーまたはクライアントライブラリはありません。両端にキャッシュとチャンクがありますが、それでも関連があります。)

  • カーソルを正しく実行するのは困難です。集計関数でGROUP BY句を使用する、カーソルを使用する動機付けとなる大きな結果セットを持つクエリを検討してください。 (このようなクエリはデータウェアハウスでは一般的です)。 GROUP BYは、結果セット全体を一度に生成して保存する必要があるため、サーバーを完全に破壊する可能性があります。他のテーブルのロックを保持している場合もあります。

経験則:

  • すばやく作成された小さな結果セットで作業する場合は、カーソルを使用しないでください。
  • カーソルは、結果セットが大きく一貫性の要件が低い、アドホックで複雑な(参照用の)シーケンシャルなクエリに優れています。

「シーケンシャルな性質」とは、クエリの重いGROUP BY句に集約関数がないことを意味します。サーバーは、カーソルがキャッシュから消費する間に10行を計算し、その間に他の処理を行うことを遅延的に決定できます。

HTH

47
AndreasT

カーソルは、セット内のレコードを繰り返すことができるツールです。 ordercurrent recordの概念があります。

一般に、SQLはマルチセットで動作します。これらは、全体としてとられた順序なしで繰り返しレコードのセットである可能性があります。

たとえば、次のクエリ:

SELECT  *
FROM    a
JOIN    b
ON      b.a = a.id

、マルチセットaおよびbで動作します。

このクエリでは、レコードの順序、レコードの保存方法、アクセスする順序などについて何も仮定していません。

これにより、実装の詳細を抽象化し、システムがこのクエリを実行するために最適なアルゴリズムを選択できるようにします。

ただし、すべてのデータを変換した後、最終的には順番に1つずつレコードにアクセスする必要があります。

電話帳のエントリがハードドライブにどのように保存されるかは気にしませんが、プリンタではアルファベット順にフィードする必要があります。書式タグは各レコードに個別に適用する必要があります。

それがまさにカーソルが作用する場所です。クライアント側で結果セットを処理するたびに、カーソルを使用しています。サーバーからメガバイトのソートされていないデータを取得することはありません。小さな変数:結果セット記述子を取得し、次のように記述します。

while (!rs.EOF) {
   process(rs);
   rs.moveNext();
}

これがすべてあなたのためにこれを実装するカーソルです。

もちろん、これはデータベースとクライアントの相互作用に関するものです。

データベース自体については:insideデータベースでは、カーソルはほとんど必要ありません。前述したように、ほとんどすべてのデータ変換は集合演算を使用してより効率的に実装できるためです。

ただし、例外があります。

  • SQL Serverの分析操作の実装は非常に不十分です。たとえば、カーソルを使用すると、集合ベースの操作を使用するよりもはるかに効率的に累積合計を計算できます
  • チャンク単位でデータを処理しています。セットベースの操作をセットのportionに順次適用し、各チャンクの結果を個別にコミットする必要がある場合があります。セットベースの操作を使用して実行することも可能ですが、多くの場合、カーソルを使用する方がより好ましい方法です。
  • Recursionネイティブでサポートしていないシステムで。

また、この記事を読む価値があるかもしれません。

27
Quassnoi

カーソルを使用すると、一連のデータをプログラムで順番に読み取ることができるため、SQLのセットベースの動作特性ではなく、従来のファイルアクセスと同様に動作します。

これが役立ついくつかの状況があります。

  1. ファイルベースのレコードアクセス動作をシミュレートする必要がある場合-たとえば、データストレージにインデックス付きファイルを使用するために以前に記述されたコードのデータストレージメカニズムとしてリレーショナルデータベースが使用されている場合。

  2. データを順番に処理する必要がある場合-簡単な例は、特定の顧客の現在の合計残高を計算することです。 (OracleやSQLServerなどの多くのリレーショナルデータベースには、この必要性を大幅に削減するSQLの分析拡張機能があります。)

必然的に、ウィキペディアにはもっとあります: http://en.wikipedia.org/wiki/Database_cursor

3
user359040

セットベースのロジックは、非常に複雑で不透明になる場合があります。これらの場合、およびパフォーマンスが問題にならない場合は、サーバー側カーソルを使用して、リレーショナルロジックをより管理しやすく使い慣れた(非リレーショナル思考者にとって)手続き型ロジックに置き換えて、メンテナンスを容易にすることができます。

1
Clodoaldo Neto

カーソルを使用すると、一度に1行にアクセスできます。そのため、一度に1行だけで多くの行を操作する場合に使用すると便利です。

私は私のクラスで、カーソルを使用する理由は、メモリに収まるよりも多くの行にアクセスしたいので、すべての行をコレクションに入れてループすることはできないということです。

1
Hurda