SQL 2005/2008 の使用
前方カーソルを使用する必要がありますが、パフォーマンスの低下は避けたいです。カーソルを使用せずにループできる高速な方法はありますか?
SQL 2005/2008 の使用
前方カーソルを使用する必要がありますが、パフォーマンスの低下は避けたいです。カーソルを使用せずにループできる高速な方法はありますか?
「NEVER use Cursors」は、単純なルールがいかに有害であるかを示す素晴らしい例です。はい、コミュニケーションは簡単ですが、「従うのが簡単」なルールを作るためにルールの理由を取り除くと、ほとんどの人はルールを考えずに盲目的にルールに従うだけになります。マイナスの影響。
カーソルは、少なくとも SQL Server / T-SQL では大きく誤解されています。「カーソルは SQL のパフォーマンスに影響を与える」と言うのは正確ではありません。確かにその傾向はありますが、その多くは人々の使い方に関係しています。適切に使用すると、カーソルはループよりも高速で効率的で、エラーが発生しにくくなりWHILE
ます (そうです、これは真実であり、「カーソルは悪である」と誰が主張しようとも、何度も何度も証明されています)。
最初のオプションは、問題に対するセットベースのアプローチを見つけようとすることです。
論理的にセットベースのアプローチがなく (たとえばEXEC
、各行ごとに呼び出す必要がある)、カーソルのクエリが実際の (一時的ではない) テーブルにヒットしている場合は、ステートメントの結果を内部テーブルにSTATIC
入れるキーワードを使用します。SELECT
したがって、結果を反復処理するときにクエリのベーステーブルをロックしません。デフォルトでは、カーソルはクエリの基礎となるテーブルの変更に「敏感」であり、呼び出し時にそれらのレコードがまだ存在することを確認しますFETCH NEXT
(したがって、カーソルがしばしば遅いと見なされる理由の大部分)。結果セットの処理中に消える可能性のあるレコードに注意する必要がある場合は、使用してSTATIC
も役に立ちませんが、WHILE
一時テーブルに対してループします (基になるデータへの変更も認識されないため)。
カーソルのクエリが一時テーブルおよび/またはテーブル変数からのみ選択している場合、これらの場合には同時実行性の問題がないため、ロックを防止する必要はありませFAST_FORWARD
んSTATIC
。
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;
ループを実行することはできますが、WHILE
反復的なSQLのすべてがパフォーマンスの問題の影響を受けるため、よりセットベースの操作を実現するように努める必要があります。
@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
前方カーソルを使用する必要がありますが、パフォーマンスの低下は避けたいです。カーソルを使用せずにループできる高速な方法はありますか?
これは、カーソルで何をするかによって異なります。
セットベースの操作を使用してほとんどすべてを書き換えることができます。この場合、ループはクエリ プラン内で実行され、コンテキスト スイッチが含まれないため、はるかに高速になります。
ただし、SQL Server
累積値の計算や日付範囲の結合など、苦手なことがあります。
これらの種類のクエリは、次を使用して高速化できますCURSOR
。
ただし、これは非常にまれな例外であり、通常はセットベースの方法の方がパフォーマンスが高くなります。
クエリを投稿した場合、おそらくそれを最適化し、CURSOR
.
カーソルを使用しないでください。代わりに、セットベースのソリューションを探してください。セットベースのソリューションが見つからない場合でも、カーソルは使用しないでください。あなたが達成しようとしていることの詳細を投稿すると、誰かがあなたのためのセットベースのソリューションを見つけることができます.
目的によっては、集計表を使用できる場合があります。
Jeff Moden がタリー テーブルに関する優れた記事を掲載しています。