129

オーバーヘッドと不便さのためにカーソルを使用する必要を避けたいと思うことは理解できますが、人々がカーソルを使用する必要を避けるために多大な努力をしている深刻なカーソル恐怖症が起こっているようです.

たとえば、ある質問では、カーソルを使用して明らかに些細なことを行う方法を尋ねられ、受け入れられた回答は、処理できる行数が 32 に制限されていても、再帰カスタム関数を使用した共通テーブル式 (CTE) 再帰クエリを使用して提案されました。 (SQL Server の再帰関数呼び出し制限のため)。これは、単純なカーソルの使用を避けるためだけに多大な努力が必要であることは言うまでもなく、システムの寿命を延ばすための恐ろしい解決策であると私は思います。

このレベルの非常識な憎しみの理由は何ですか? いくつかの「著名な権威」がカーソルに対してファトワを発行しましたか? カーソルの心臓部には、子供のモラルを堕落させる言葉にできない悪が潜んでいるのでしょうか?

Wiki の質問、担当者よりも回答に興味があります。

関連情報:

SQL Server 早送りカーソル

編集:もっと正確に言うと、通常のリレーショナル操作の代わりにカーソルを使用すべきではないことを理解しています。それは簡単です。私が理解していないのは、カーソルがより単純で/またはより効率的なソリューションである場合でも、カーソルを避けるために邪魔にならない人がいるということです。私を困惑させているのは、明らかな技術的効率ではなく、不合理な憎しみです。

4

13 に答える 13

74

カーソルの「オーバーヘッド」は、API の一部にすぎません。カーソルは、RDBMS の一部が内部でどのように機能するかです。多くの場合CREATE TABLE、ステートメントINSERTSELECTあり、実装は明らかな内部カーソルの実装です。

より高いレベルの「セットベースの演算子」を使用すると、カーソルの結果が 1 つの結果セットにまとめられます。つまり、API のやり取りが少なくなります。

カーソルは、ファーストクラスのコレクションを提供する最新の言語よりも前から存在します。古いC、COBOL、Fortranなどには、広く使える「コレクション」という概念がなかったため、行を1つずつ処理する必要がありました。Java、C#、Python などには、結果セットを格納する第一級のリスト構造があります。

遅い問題

一部のサークルでは、リレーショナル結合は謎であり、人々は単純な結合ではなくネストされたカーソルを作成します. 私は本当に壮大なネストされたループ操作がたくさんのカーソルとして書き出されるのを見てきました。RDBMS 最適化の無効化。そして走るのは本当にゆっくり。

ネストされたカーソル ループを結合に置き換える単純な SQL リライトと、単一のフラット カーソル ループにより、プログラムを 100 分の 1 の時間で実行できます。[彼らは私が最適化の神だと思っていました。私がしたことは、ネストされたループを結合に置き換えることだけでした。まだカーソルを使用しています。]

この混乱は、多くの場合、カーソルの起訴につながります。ただし、問題はカーソルではなく、カーソルの誤用です。

サイズの問題

非常に壮大な結果セット (つまり、テーブルをファイルにダンプする) には、カーソルが不可欠です。セットベースの操作では、非常に大きな結果セットをメモリ内の単一のコレクションとして具体化することはできません。

代替案

可能な限り ORM レイヤーを使用するようにしています。しかし、それには2つの目的があります。まず、カーソルは ORM コンポーネントによって管理されます。次に、SQL がアプリケーションから構成ファイルに分離されます。カーソルが悪いわけではありません。これらすべてのオープン、クローズ、フェッチをコーディングすることは、付加価値プログラミングではありません。

于 2008-11-13T16:52:42.947 に答える
42

カーソルは、セットベースの環境に手続き型の考え方を過度に適用させます。

そして、彼らは遅いです!!!

SQLTeamから:

カーソルは、SQL Server 内のデータにアクセスする最も遅い方法であることに注意してください。は、一度に 1 行ずつアクセスする必要がある場合にのみ使用してください。私が考えることができる唯一の理由は、各行でストアド プロシージャを呼び出すことです。Cursor Performanceの記事で、カーソルはセット ベースの代替手段よりも 30 倍以上遅いことを発見しました。

于 2008-11-13T16:41:24.203 に答える
20

上記の回答には、「カーソルは SQL Server 内のデータにアクセスする最も遅い方法です... カーソルは、セットベースの代替手段よりも 30 倍以上遅いです」と書かれています。

このステートメントは多くの状況で正しいかもしれませんが、包括的なステートメントとしては問題があります. たとえば、本番環境で絶え間なく読み取りを受信して​​いる大きなテーブルの多くの行に影響を与える更新または削除操作を実行したい状況で、カーソルをうまく利用しました。これらの更新を一度に 1 行ずつ実行するストアド プロシージャを実行すると、セット ベースの操作よりも高速になります。極端な場合)。

他のデータベース アクティビティがない場合は、セットベースの操作の方が一般的に高速です。本番システムでは、状況によって異なります。

于 2008-11-13T16:48:09.743 に答える
9

カーソルは、セットベースの操作が適している場所で、初心者の SQL 開発者によって使用される傾向があります。特に、従来のプログラミング言語を学習した後に SQL を学習する場合、「これらのレコードを繰り返し処理する」という考え方により、カーソルを不適切に使用する傾向があります。

ほとんどの本格的な SQL 書籍には、カーソルの使用を禁止する章が含まれています。よく書かれたものは、カーソルがその場所を持っていることを明確にしますが、セットベースの操作には使用しないでください。

カーソルが正しい選択である、または少なくとも正しい選択である状況が明らかにあります。

于 2008-11-13T16:43:29.707 に答える
9

カーソル方式が使用されている場合、オプティマイザーは、関係代数を使用して問題を変換できないことがよくあります。多くの場合、カーソルは問題を解決するための優れた方法ですが、SQL は宣言型言語であり、制約から統計やインデックスまで、データベースには多くの情報があります。つまり、オプティマイザには問題を解決するための多くのオプションがあります。問題ですが、カーソルはかなり明示的に解決策を指示します。

于 2008-11-13T16:44:52.887 に答える
8

Oracle PL/SQL カーソルでは、テーブル ロックが発生せず、一括収集/一括フェッチを使用できます。

Oracle 10 では、よく使用される暗黙カーソル

  for x in (select ....) loop
    --do something 
  end loop;

一度に 100 行を暗黙的にフェッチします。明示的なバルク収集/バルクフェッチも可能です。

ただし、PL/SQL カーソルは最後の手段です。セットベースの SQL で問題を解決できない場合に使用してください。

もう 1 つの理由は並列化です。データベースは、行ごとの命令型コードよりも大きなセットベースのステートメントを並列化する方が簡単です。関数型プログラミング (Haskell、F#、Lisp、C# LINQ、MapReduce ...) がますます一般的になるのと同じ理由で、関数型プログラミングは並列化を容易にします。コンピューターあたりの CPU の数が増加しているため、並列化がますます問題になっています。

于 2009-01-10T13:08:21.167 に答える
6

上記の回答は、ロックの重要性を十分に強調していません。テーブル レベルのロックが発生することが多いため、私はカーソルの大ファンではありません。

于 2008-12-28T16:51:08.667 に答える
6

一般に、リレーショナル データベースでは、カーソルを使用するコードのパフォーマンスは、セットベースの操作よりも桁違いに悪いためです。

于 2008-11-13T16:41:13.080 に答える
3

価値があるのは、カーソルがセットベースの対応する場所よりも実行される「1つの」場所が現在の合計にあることを読んだことです。小さなテーブルでは、列による順序よりも行を合計する速度がセットベースの操作に有利ですが、テーブルの行サイズが大きくなると、現在の合計値を次のパスに単純に運ぶことができるため、カーソルはより高速になります。ループ。現在、累計を実行する必要がある場所は別の引数です...

于 2008-11-14T00:53:46.487 に答える
2

パフォーマンス (非) の問題以外では、カーソルの最大の欠点は、デバッグが面倒なことだと思います。特に、ほとんどのクライアント アプリケーションのコードと比較すると、デバッグは比較的簡単で、言語機能ははるかに簡単です。実際、カーソルを使用して SQL で行っていることのほとんどは、最初はクライアント アプリで行われているはずだと私は主張します。

于 2009-06-09T22:55:09.720 に答える
1

そのカーソルの例や質問へのリンクを投稿できますか? おそらく、再帰的な CTE よりも優れた方法があります。

他のコメントに加えて、カーソルを不適切に使用すると (よくあることですが)、不要なページ/行ロックが発生します。

于 2008-11-13T16:45:14.180 に答える
1

あなたとは異なる視点を持っているという理由だけで人々を「狂人」と呼ぶのではなく、おそらく2番目の段落の後に質問を締めくくることができたでしょう。

あなたの質問に関しては、カーソルが必要になる状況は確かにありますが、私の経験では、開発者はカーソルを実際よりも頻繁に使用する必要があると判断しています。私の意見では、誰かがカーソルを使いすぎて過ちを犯す可能性と、カーソルを使用すべきときに使用しない可能性ははるかに高くなります。

于 2008-11-13T17:55:37.453 に答える
0

基本的に、同じことを行う2ブロックのコード。多分それは少し奇妙な例ですが、それは要点を証明しています。SQL Server 2005:

SELECT * INTO #temp FROM master..spt_values
DECLARE @startTime DATETIME

BEGIN TRAN 

SELECT @startTime = GETDATE()
UPDATE #temp
SET number = 0
select DATEDIFF(ms, @startTime, GETDATE())

ROLLBACK 

BEGIN TRAN 
DECLARE @name VARCHAR

DECLARE tempCursor CURSOR
    FOR SELECT name FROM #temp

OPEN tempCursor

FETCH NEXT FROM tempCursor 
INTO @name

SELECT @startTime = GETDATE()
WHILE @@FETCH_STATUS = 0
BEGIN

    UPDATE #temp SET number = 0 WHERE NAME = @name
    FETCH NEXT FROM tempCursor 
    INTO @name

END 
select DATEDIFF(ms, @startTime, GETDATE())
CLOSE tempCursor
DEALLOCATE tempCursor

ROLLBACK 
DROP TABLE #temp

1回の更新には156ミリ秒かかりますが、カーソルには2016ミリ秒かかります。

于 2008-11-13T16:56:39.787 に答える