私が直面したインタビューの質問に基づいています。
非常に短い定義は
クエリによって返される行を操作するために使用できます。
カーソルの使用に加えて (ポイントは MSDN にリストされています)、クエリまたはストアド プロシージャを使用してすべての操作を実行できるかどうかという質問があります (私が間違っていなければ、Transact-SQL を使用できるように) ms-sql の場合)、カーソルを使用する具体的なポイントはありますか?
私が直面したインタビューの質問に基づいています。
非常に短い定義は
クエリによって返される行を操作するために使用できます。
カーソルの使用に加えて (ポイントは MSDN にリストされています)、クエリまたはストアド プロシージャを使用してすべての操作を実行できるかどうかという質問があります (私が間違っていなければ、Transact-SQL を使用できるように) ms-sql の場合)、カーソルを使用する具体的なポイントはありますか?
大きな結果セットと比較してカーソルを使用することは、ビデオを一気にダウンロードする代わりにビデオ ストリーミングを使用し、ダウンロードされたときにそれを見るようなものです。ダウンロードする場合は、数ギガの容量と、ダウンロードが完了するまで待つ忍耐力が必要です。現在、マシンやネットワークがどれほど高速であっても、誰もが同じ速度で映画を見ています。
通常、クエリはサーバーに送信され、実行され、結果セットがネットワーク経由で 1 回のアクティビティで送信されます。カーソルは、行ごとにデータにアクセスし、要求した場合にのみすべての行をストリーミングします (実際に表示できます)。
ただし、いくつかの注意点があります。
一貫性: カーソルを使用すると、(通常) データの一貫したスナップショットではなく、行で操作します。したがって、同時実行/一貫性/分離の保証は、データベース全体 (ACID) から 1 行のみに低下します。通常、必要な並行処理のレベルを DBMS に通知できますが、細心の注意を払う (現在のテーブル全体をロックする) と、サーバー側で節約できるリソースの多くが失われます。
すべての行を単独で送信することは、非常に非効率的です。なぜなら、すべてのパケットにはネゴシエーション オーバーヘッドがあり、パケットごとに圧縮された大きなデータ チャンクを送信することで回避できる可能性があるからです。(DBサーバーやクライアントライブラリは、すべての行を個別に送信するほど愚かではありません。両端にキャッシュとチャンクがありますが、それでも関連しています。)
カーソルを正しく操作するのは難しくなります。集計関数で GROUP BY 句を使用する、カーソルを使用する動機となる、大きな結果セットを持つクエリを考えてみましょう。(このようなクエリは、データ ウェアハウスでは一般的です)。GROUP BY は、結果セット全体を一度に生成して保存する必要があり、おそらく他のテーブルのロックを保持する必要があるため、サーバーを完全に破壊する可能性があります。
経験則:
「シーケンシャルな性質」とは、クエリの重い GROUP BY 句に集計関数がないことを意味します。サーバーは、カーソルがキャッシュから消費し、その間に他の処理を行うために 10 行を計算することを遅延して決定できます。
HTH
カーソルは、セット内のレコードを反復処理できるツールです。順序と現在 の 記録の 概念 を 持 つ。
通常、マルチセットでSQL
動作します。これらは、特定の順序で繰り返される可能性のあるレコードのセットであり、全体として取られます。
たとえば、次のクエリを実行します。
SELECT *
FROM a
JOIN b
ON b.a = a.id
a
、マルチセットおよびで動作しb
ます。
このクエリでは、レコードの順序、格納方法、アクセス順序などについて、何も仮定していません。
これにより、実装の詳細を抽象化し、システムがこのクエリを実行するための最適なアルゴリズムを選択できるようになります。
ただし、すべてのデータを変換した後、最終的には順番に 1 つずつレコードにアクセスする必要があります。
電話帳のエントリがハード ドライブにどの程度正確に格納されているかは問題ではありませんが、プリンタではアルファベット順に入力する必要があります。また、書式タグは各レコードに個別に適用する必要があります。
それがまさにカーソルの出番です。クライアント側で結果セットを処理するたびに、カーソルを使用しています。サーバーからメガバイト単位のソートされていないデータを取得することはありません。小さな変数 (結果セット記述子) を取得するだけで、次のように記述できます。
while (!rs.EOF) {
process(rs);
rs.moveNext();
}
これは、これらすべてを実装するカーソルです。
もちろん、これはデータベースとクライアントの相互作用に関係しています。
データベース自体については、データベース内でカーソルが必要になることはめったにありません。なぜなら、上で述べたように、ほとんどすべてのデータ変換は集合演算を使用してより効率的に実装できるからです。
ただし、例外があります。
SQL Server
実装は非常に不十分です。たとえば、累積合計は、セットベースの操作を使用するよりもカーソルを使用した方がはるかに効率的に計算できます。この記事も読む価値があります。
カーソルを使用すると、プログラムによって一連のデータを順次読み取ることができるため、SQL のセットベースの動作特性ではなく、従来のファイル アクセスと同様の方法で動作します。
これが役立つ状況がいくつかあります。
ファイルベースのレコード アクセス動作をシミュレートする必要がある場合 - たとえば、データ ストレージにインデックス付きファイルを使用するように以前に記述されたコード片のデータ ストレージ メカニズムとしてリレーショナル データベースが使用されている場合。
データを順次処理する必要がある場合 - 簡単な例として、特定の顧客の累計残高を計算する場合があります。(Oracle や SQLServer などの多くのリレーショナル データベースには、現在、SQL に対する分析拡張機能があり、この必要性が大幅に削減されます。)
必然的に、ウィキペディアにはさらに多くの情報があります: http://en.wikipedia.org/wiki/Database_cursor
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.
カーソルを使用すると、一度に 1 行ずつアクセスできます。そのため、多数の行を操作したいが、一度に 1 つしか操作したくない場合に使用するとよいでしょう。
私はクラスで、カーソルを使用する理由は、メモリに収まるよりも多くの行にアクセスしたいためであると言われました。そのため、すべての行をコレクションに入れてループすることはできません。