50

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

非常に短い定義は

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

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

4

5 に答える 5

61

大きな結果セットと比較してカーソルを使用することは、ビデオを一気にダウンロードする代わりにビデオ ストリーミングを使用し、ダウンロードされたときにそれを見るようなものです。ダウンロードする場合は、数ギガの容量と、ダウンロードが完了するまで待つ忍耐力が必要です。現在、マシンやネットワークがどれほど高速であっても、誰もが同じ速度で映画を見ています。

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

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

ただし、いくつかの注意点があります。

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

  • すべての行を単独で送信することは、非常に非効率的です。なぜなら、すべてのパケットにはネゴシエーション オーバーヘッドがあり、パケットごとに圧縮された大きなデータ チャンクを送信することで回避できる可能性があるからです。(DBサーバーやクライアントライブラリは、すべての行を個別に送信するほど愚かではありません。両端にキャッシュとチャンクがありますが、それでも関連しています。)

  • カーソルを正しく操作するのは難しくなります。集計関数で GROUP BY 句を使用する、カーソルを使用する動機となる、大きな結果セットを持つクエリを考えてみましょう。(このようなクエリは、データ ウェアハウスでは一般的です)。GROUP BY は、結果セット全体を一度に生成して保存する必要があり、おそらく他のテーブルのロックを保持する必要があるため、サーバーを完全に破壊する可能性があります。

経験則:

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

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

HTH

于 2012-04-04T14:20:49.560 に答える
31

カーソルは、セット内のレコードを反復処理できるツールです。順序現在 の 記録の 概念 を 持 つ。

通常、マルチセットでSQL動作します。これらは、特定の順序で繰り返される可能性のあるレコードのセットであり、全体として取られます。

たとえば、次のクエリを実行します。

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

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

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

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

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

電話帳のエントリがハード ドライブにどの程度正確に格納されているかは問題ではありませんが、プリンタではアルファベット順に入力する必要があります。また、書式タグは各レコードに個別に適用する必要があります。

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

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

これは、これらすべてを実装するカーソルです。

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

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

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

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

この記事も読む価値があります。

于 2010-10-05T12:41:15.443 に答える
4

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

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

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

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

必然的に、ウィキペディアにはさらに多くの情報があります: http://en.wikipedia.org/wiki/Database_cursor

于 2010-10-05T12:05:49.970 に答える
1

Sometimes a set based logic can get quite complex and opaque. In these cases and if the performance is not an issue a server side cursor can be used to replace the relational logic with a more manageable and familiar (to a non relational thinker) procedural logic resulting in easier maintenance.

于 2012-04-04T14:41:37.533 に答える
1

カーソルを使用すると、一度に 1 行ずつアクセスできます。そのため、多数の行を操作したいが、一度に 1 つしか操作したくない場合に使用するとよいでしょう。

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

于 2010-10-05T07:22:05.030 に答える