11

SQL 2005/2008 の使用

前方カーソルを使用する必要がありますが、パフォーマンスの低下は避けたいです。カーソルを使用せずにループできる高速な方法はありますか?

4

9 に答える 9

6

「NEVER use Cursors」は、単純なルールがいかに有害であるかを示す素晴らしい例です。はい、コミュニケーションは簡単ですが、「従うのが簡単」なルールを作るためにルールの理由を取り除くと、ほとんどの人はルールを考えずに盲目的にルールに従うだけになります。マイナスの影響。

カーソルは、少なくとも SQL Server / T-SQL では大きく誤解されています。「カーソルは SQL のパフォーマンスに影響を与える」と言うのは正確ではありません。確かにその傾向はありますが、その多くは人々の使い方に関係しています。適切に使用すると、カーソルはループよりも高速で効率的で、エラーが発生しにくくなりWHILEます (そうです、これは真実であり、「カーソルは悪である」と誰が主張しようとも、何度も何度も証明されています)。

最初のオプションは、問題に対するセットベースのアプローチを見つけようとすることです。

論理的にセットベースのアプローチがなく (たとえばEXEC、各行ごとに呼び出す必要がある)、カーソルのクエリが実際の (一時的ではない) テーブルにヒットしている場合は、ステートメントの結果を内部テーブルにSTATIC入れるキーワードを使用します。SELECTしたがって、結果を反復処理するときにクエリのベーステーブルをロックしません。デフォルトでは、カーソルはクエリの基礎となるテーブルの変更に「敏感」であり、呼び出し時にそれらのレコードがまだ存在することを確認しますFETCH NEXT(したがって、カーソルがしばしば遅いと見なされる理由の大部分)。結果セットの処理中に消える可能性のあるレコードに注意する必要がある場合は、使用してSTATICも役に立ちませんが、WHILE一時テーブルに対してループします (基になるデータへの変更も認識されないため)。

カーソルのクエリが一時テーブルおよび/またはテーブル変数からのみ選択している場合、これらの場合には同時実行性の問題がないため、ロックを防止する必要はありませFAST_FORWARDSTATIC

LOCAL READ_ONLY FORWARD_ONLYこれらの 1 つ以上ではないカーソルが特に必要な場合を除き、 の 3 つのオプションを指定することも役立つと思います。ただし、パフォーマンスが向上するかどうかはテストしていません。

操作をセットベースにするのに適していないと仮定すると、次のオプションはほとんどの操作の出発点として適しています。

DECLARE [Thing1] CURSOR LOCAL READ_ONLY FORWARD_ONLY STATIC
FOR SELECT columns
    FROM   Schema.ReadTable(s);


DECLARE [Thing2] CURSOR LOCAL READ_ONLY FORWARD_ONLY FAST_FORWARD
FOR SELECT columns
    FROM   #TempTable(s) and/or @TableVariables;
于 2011-03-24T21:45:41.787 に答える
5

ループを実行することはできますが、WHILE反復的なSQLのすべてがパフォーマンスの問題の影響を受けるため、よりセットベースの操作を実現するように努める必要があります。

http://msdn.microsoft.com/en-us/library/ms178642.aspx

于 2011-03-24T21:20:05.923 に答える
4

@Neilが提案したように、Common Table Expressionsは良い代替手段です。Adventureworks の例を次に示します。

WITH cte_PO AS 
(
SELECT [LineTotal]
  ,[ModifiedDate]
FROM [AdventureWorks].[Purchasing].[PurchaseOrderDetail]
),
minmax AS
(
    SELECT MIN([LineTotal]) as DayMin
        ,MAX([LineTotal]) as DayMax
        ,[ModifiedDate]
    FROM cte_PO
    GROUP BY [ModifiedDate]
)
SELECT * FROM minmax ORDER BY ModifiedDate

返されるものの上部の数行は次のとおりです。

DayMin     DayMax     ModifiedDate
135.36     8847.30    2001-05-24 00:00:00.000
129.8115   25334.925  2001-06-07 00:00:00.000
于 2011-03-25T02:12:25.890 に答える
3

前方カーソルを使用する必要がありますが、パフォーマンスの低下は避けたいです。カーソルを使用せずにループできる高速な方法はありますか?

これは、カーソルで何をするかによって異なります。

セットベースの操作を使用してほとんどすべてを書き換えることができます。この場合、ループはクエリ プラン内で実行され、コンテキスト スイッチが含まれないため、はるかに高速になります。

ただし、SQL Server累積値の計算や日付範囲の結合など、苦手なことがあります。

これらの種類のクエリは、次を使用して高速化できますCURSOR

ただし、これは非常にまれな例外であり、通常はセットベースの方法の方がパフォーマンスが高くなります。

クエリを投稿した場合、おそらくそれを最適化し、CURSOR.

于 2011-03-25T11:22:05.593 に答える
2

共通テーブル式を使用した再帰クエリ

于 2011-03-24T21:19:45.950 に答える
2

カーソルを使用しないでください。代わりに、セットベースのソリューションを探してください。セットベースのソリューションが見つからない場合でも、カーソルは使用しないでください。あなたが達成しようとしていることの詳細を投稿すると、誰かがあなたのためのセットベースのソリューションを見つけることができます.

于 2011-03-25T11:14:13.787 に答える
2

目的によっては、集計表を使用できる場合があります。

Jeff Moden がタリー テーブルに関する優れた記事を掲載しています

于 2011-03-24T22:00:23.533 に答える