39

ストアド プロシージャなどを作成したときに、最初は CURSOR を使用していたことが何度もありましたが、後でプロシージャのパフォーマンスの問題を発見しました。

私が読んだすべてのことは、CURSORSがひどい、不必要なロックを引き起こすなどと言っており、パフォーマンステストでも同じことが証明されています。

私の質問は、いつ CURSOR を使用し、どのような状況でそれらが有用または優れているかということです。

役に立たないのなら、なぜ彼らは SQL のためにそのような悪い制御構造/型を作るのでしょうか?

4

9 に答える 9

39

通常は避けるべきですが、機能には理由があり、使用する場合もあります。私が見たカーソルの 90% 以上は必要ないと思います。それらをCRUD操作に使用している場合、ほとんどの場合、セットベースの方法でやり直すことができます. 更新または削除で結合を使用する方法を知らないため、または挿入で値句の代わりに選択ステートメントを使用できるため、これにカーソルを使用する人をよく見てきました。case ステートメントで実際には簡単に処理できる、もう少し複雑な処理のためにそれらが必要だと人々が考える場合のもう 1 つの不必要な使用。

カーソルは、現在の合計などを計算する場合により高速になることがあります。

カーソルは、一度に 1 つの入力値のみを処理するように設定されたストアド プロシージャを複数回実行する場合にも便利です。私はこの機能をユーザー ストアド プロシージャの実行には使用しません (非常に小さなデータ セットをヒットすることがわかっている場合を除きます) が、複数のテーブルに対してシステム プロシージャを実行する必要がある場合、データベース管理者にとって非常に便利です。

SQl でメールを作成している場合 (これを行うのに最適な場所ではありませんが、一部のシステムではそれを行っています)、メールの受信者全体にリストの他の人を表示したくない場合、またはそれぞれをパーソナライズしたい場合宛先に関する情報を電子メールで送信する場合は、カーソルが最適です。

セットベースの挿入/更新/削除全体に時間がかかりすぎてテーブルがロックされる場合は、カーソルまたはループを使用してレコードのバッチを処理することもできます。これは、カーソルとセットベースのソリューションの一種のハイブリッドであり、多くの場合、実稼働システムでの大規模な変更に最適です。

于 2009-09-25T21:55:56.240 に答える
9

以前、SQL Server チームの担当者に尋ねたことがあります。すべての人にとって製品をより良くする機能を 1 つ追加できるとしたら、それは何ですか?

彼の反応は「追加?ええと、私は1つを奪います。カーソルをなくすと、世界中のプログラマーが SET ベースの方法で物事を考え始めることになり、DB パフォーマンスがこれまでにないほど世界規模で向上することになります。」

しかし、私の場合はパターンが見られる傾向があります。一度に 1 つの要素を操作できるようにする必要があり、古いファッションの WHILE ループの概念を見逃しているため、カーソルを使用するプロシージャル コーダーがたくさんいるようです。カーソルのオーバーヘッドがない基本的な考え方は同じです。まだSETベースのものほど高速/効果的ではありませんが、誰かが「このセットベースを行うことはできません。カーソルを使用する必要があります」と主張する時間の90%は、whileループで実行させることができます.

于 2009-09-25T21:35:25.887 に答える
1

これは、かなり独断的な仲間による記事で、カーソルを使用しない理由と、カーソルがどのようになったかについてのいくつかの答えを示しています: There Must be 15 Ways to Lose Your Cursors .

于 2009-09-25T21:35:18.767 に答える
1

私が勉強している SQL Server 2008 の MCTS prep マニュアルでは、特に SQL Server 2008 がカスタム集計関数をサポートするようになったので、T-SQL で CURSOR が必要な場所ならどこでも外部 CLR コードを使用することを推奨しています。

5 年前、私は彼らと一緒に広範なレポート機能を開発しましたが、今ではそれらの適切な使用例を思いつくことができなかったと思います。CLR の集計と関数は、組み込みの集計関数と同様に機能します。

于 2009-09-25T21:55:04.830 に答える
1

OMG、どうして Group By を忘れたのですか? 以下に示すカーソルベースのクエリを取得し、その後のクエリに置き換えました。単一の結果セットを取得するようになったので、php で sqlsrv_next_result() を使用しても問題はありません。

DECLARE @thisday datetime;

DECLARE daycursor CURSOR FOR
SELECT DISTINCT DATEADD(day, 0, DATEDIFF(day, 0, TimeCollected)) as thisday
FROM computerusedata

OPEN daycursor;
FETCH NEXT FROM daycursor
INTO @thisday;
WHILE @@FETCH_STATUS = 0
    BEGIN
    select distinct left(ComputerName,5) as CompGroup,DATEADD(day, 0, DATEDIFF(day, 0, TimeCollected)) as day
    FROM computerusedata
    where DATEADD(day, 0, DATEDIFF(day, 0, TimeCollected)) = @thisday
    order by CompGroup;
    FETCH NEXT FROM daycursor;
    END;
CLOSE daycursor;
DEALLOCATE daycursor;";


select DATEADD(day, 0, DATEDIFF(day, 0, TimeCollected)) as day,left(ComputerName,5) as CompGroup
from ComputerUseData
group by DATEADD(day, 0, DATEDIFF(day, 0, TimeCollected)),left(ComputerName,5)
order by day,CompGroup
于 2013-10-03T21:50:56.413 に答える
1

私がそれらを使用するのは、カーソル内で行われたことを一度に 1 項目ずつ実行する必要があり、カーソル内で行われたことが非常に長くかかるため、カーソルのオーバーヘッドが取るに足らないものになる場合だけです。

データベースのバックアップ、整合性チェック、インデックスの再構築など。要するに、管理タスク。

于 2009-09-26T08:05:42.410 に答える
0

私は通常カーソルを使用しませんが、使用する場合は、ローカルで実行している「1回限りの」クエリまたは毎日のジョブである必要があります。Web要求への応答のように頻繁に呼び出されるカーソルを、実動コードで呼び出さないようにする必要があります。

于 2009-09-25T21:36:50.883 に答える
0

セットベースの操作としてALTER INDEX...
を実行する方法がない限り、テーブル インデックスを個別に再構築または再編成するためにカーソルを使用します。

于 2009-09-26T15:03:01.777 に答える
0

カーソルは、1) set 操作では実行できないことを行う必要がある場合、または 2) アプリケーション層から繰り返し呼び出しを行って同じ作業を行う意味がない場合に役立ちます。または、データベース層に残す必要がある手順があり、途中でアプリケーション層に戻って結果セットを反復処理することができない場合もあります。

ただし、通常のカーソルを取り巻くカーソルの割り当て/割り当て解除の問題を回避できるため、通常のカーソルではなくカーソル変数を使用することをお勧めします。通常のカーソルでは、割り当てを解除しないと保持され、メモリ リークの原因となる可能性があります。変数ベースのカーソル (つまり、DECLARE @cursor CURSOR) ではそうではありません。

肝心なのは、可能であればそれらを避け、それができない場合は、それらを最小限かつ賢明に使用することです.

于 2009-09-25T21:56:54.523 に答える