web-dev-qa-db-ja.com

MS SQL Server-カーソルはいつ有効ですか?

ストアドプロシージャなどを作成したことがよくあります。最初にカーソルを使用し、後でプロシージャのパフォーマンスの問題を見つけました。

私が読んだすべてのものは、カーソルがひどい、不必要なロックなどを引き起こしていると言い、パフォーマンステストは同じことを証明します。

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

役に立たないのに、なぜSQLにこのような悪い制御構造/タイプを作成するのでしょうか?

39
jonathanpeppers

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

実行中の合計などを計算する場合、カーソルの方が速い場合があります。

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

SQlでメールを作成している(それを行うのに最適な場所ではないが、システムによってはメールを作成する場所にある)場合、メールの対象者全員にリスト上の他の人を表示したくない、またはそれぞれをパーソナライズしたい場合宛先に関する情報を電子メールで送信し、カーソルを使用する方法です。

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

37
HLGEM

SQL Serverチームの担当者に、製品をすべての人にとってより良いものにする1つの機能を追加できるかどうか尋ねました。

彼の返答は「追加?ええと、私は一つを奪うでしょう。カーソルを取り除くと、世界中のプログラマーがSETベースの方法で物事について考え始めるように強いられます。これは、これまでにない世界最大のDBパフォーマンスの向上です。

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

8
keithwarren7

カーソルを使用しない理由と、それがどのようになったかについていくつかの回答を与える、かなり意見のあるフェローによる記事です: カーソルを失うには15通りの方法があるはずです

1
RBarryYoung

私がそれらを使用するのは、カーソル内で行われるすべての操作を一度に1項目ずつ行う必要がある場合と、カーソル内で行われるすべての操作に時間がかかるため、カーソルのオーバーヘッドが取るに足らないものになる場合です。

たとえば、データベースのバックアップ、整合性チェック、インデックスの再構築。つまり、管理タスクです。

1
GilaMonster

OMG、どのようにGroup Byを忘れたのですか?以下に示すカーソルベースのクエリを取り、それを後のクエリに置き換えました。今、私は単一の結果セットを取得するので、phpsで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
1
Iconiu

私が調査しているSQL Server 2008のMCTS準備マニュアルでは、T-SQLでCURSORが必要な場合はどこでも外部CLRコードを使用することをお勧めしています。SQLServer 2008がカスタム集計関数をサポートしているためです。

5年前、私は広範なレポート機能のために彼らと協力しましたが、今はそれらの良いユースケースを思い付くことができないと思います。 CLRの集計と関数は、組み込みの集計関数と同様に機能します。

1
womp

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

0
Matt Wrock

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

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

肝心なのは、可能であればそれらを避け、できなければ最小限にして賢く使用することです。

0
Dane

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

0
dance2die