4

最近、TSQLでのカーソルの使用についてこの議論があります...

まず第一に、私は議論のチアリーダーではありません。しかし、誰かがカーソルを言うたびに、義務的な「カーソルは邪悪な」というマントラで飛び跳ねるナックルヘッド(または50)が常にいます。SQL-Serverがセットベースの操作用に最適化されていることは知っています。カーソルは本当に邪悪な化身である可能性がありますが、その背後に客観的な考えを置きたい場合は...

これが私の心の行き先です:

  1. カーソルとセット操作の唯一の違いはパフォーマンスの1つですか?

    編集:IDのリストに対して単一のバッチを繰り返し実行したり、テーブルフィールドの行に格納された実際のSQLテキストを実行したりするなど、単にパフォーマンスの問題ではないという良いケースがあります。行ごと。

  2. フォローアップ:カーソルのパフォーマンスは常に低下しますか?

    • 編集:@Martinは、カーソルがセットベースの操作をかなり劇的に上回っている良いケースを示しています。これは(ある種のOLAP /データウェアハウスのようなソリューションに頼る前に)あまり頻繁に行うようなことではないと思いますが、それでも、それなしでは本当に生きていけないケースのようです。カーソル。
    • カーソルが一般的に信じられているよりも競争力があるかもしれないことを示唆するTPCベンチマークへの参照。
    • Sql-Server2005以降のカーソルのメモリ使用量の最適化への参照
  3. セットベースの操作よりもカーソルの方が解決に適しているという、考えられる問題はありますか?

    • 編集:セットベースの操作では、文字通りストアドプロシージャなどは使用できません(上記の項目1の編集を参照)。 Execute
    • 編集:セットベースの操作は、大規模なデータセットを集約する場合、行ごとよりも指数関数的に遅くなります。

  • 人々がカーソルに頼る最も一般的な問題の見方を説明するMSDNの記事(および、より適切に機能するセットベースの手法の説明)。
  • Microsoftは、MSDNの2008 Transact SQLリファレンスで(漠然と)「...結果は一度に1行ずつ処理するのが最適な場合があります」と述べていますが、どのような場合を参照しているのかについては例を挙げないでください。に。

ほとんどの場合、さまざまなアプリケーションに大幅なアップグレードを行う場合は、そこから何かが得られる限り、古いコードでカーソルをセットベースの操作に変換することを心がけています。(私は多くの場合、純粋さよりも怠惰になる傾向があります。つまり、壊れていない場合は修正しないでください。)

4

4 に答える 4

4

あなたの質問に直接答えるには:

カーソルを使って設定操作を実行できないという状況はまだ発生していません。ただし、カーソルを使用して大規模なセットの問題をより管理しやすいチャンクに分割すると、コードの保守性、ロギング、トランザクション制御などの目的でより優れたソリューションが証明される場合があります。しかし、どのタイプの要件がいずれかのソリューションにつながるかを示すための厳格なルールがあるとは思えません。個々のデータベースとニーズは単純に非常に多様です。

そうは言っても、私はあなたの「壊れていないのなら直さないでください」というアプローチに完全に同意します。手続き型コードをリファクタリングして、正常に機能しているプロシージャの操作を設定しても、得られるものはほとんどありません。ただし、最初にセットベースのソリューションを探し、必要な場合にのみ手続き型コードにドロップすることをお勧めします。腸の感触?20%以上の時間カーソルを使用している場合は、何か問題があります。

そして、私が本当に言いたいことについて:

プログラマーにインタビューするとき、私は常に、適度に複雑なSQLの質問をいくつか投げて、それらをどのように解決するかを説明するように依頼します。これらは集合演算で解決できると私が知っている問題であり、手続き的なアプローチ(つまりカーソル)なしでそれらを解決できる候補者を特に探しています。

これは、どちらのアプローチにも本質的に優れた、またはよりパフォーマンスの高いものがあると私が信じているからではありません。状況が異なれば、結果も異なります。むしろ、私の経験では、プログラマーは集合ベースの操作の概念を理解しているか、理解していないかのどちらかであるためです。そうしないと、セットベースの操作ではるかに迅速かつ簡単に解決できる問題の複雑な手続き型ソリューションの開発に多くの時間を費やすことになります。

逆に、セットベースの操作を行うプログラマー、実際に絶対に必要な場合に、手続き型ソリューションの実装に問題が発生することはほとんどありません。

于 2011-07-29T18:44:12.570 に答える
3

合計の実行は、行数が増えると、カーソルの固定コストが高くなるにもかかわらず、セットベースの「三角形結合」アプローチのように指数関数的にではなく直線的に増加するため、カーソルがセットベースの操作を実行できなくなる典型的なケースです。

ItzikBenGanはここでいくつかの比較を行います

グラフ

DenaliはOVERこの条項をより完全にサポートしていますが、この使用は冗長になるはずです。

于 2011-07-29T22:44:55.120 に答える
2

他のTSQLコンストラクト(通常は少なくとも1つのwhileループを含む)を使用してカーソルを(さまざまな形式で)再実装することができます。他のコンストラクトを使用して実行できないカーソルで実現できることは何もありません。

それは、再実装が、そのソリューションに「カーソル」という単語を含めないことによって回避されたカーソルほど非効率的ではないということではありません。一部の人々は、力学ではなく、純粋に言葉を嫌うようです。

私がカーソルを保持することに成功した場所の1つは、2つの異なるデータベース間のデータ転送/変換でした(ここではクライアントを扱っていました)。この転送をセットベースの方法で実装することもできましたが(実際、以前は実装していました)、問題のあるデータがあり、少数のクライアントに問題を引き起こす可能性がありました。セットベースのソリューションでは、次のいずれかを行う必要がありました。

  • 各テーブルで失敗したクライアントデータを除外して転送を続行し、それらのクライアントを部分的に転送したままにします。または、
  • バッチ全体を中止する

一方、転送の単位を個々のクライアントにする(カーソルを使用して各クライアントを選択する)ことにより、システム間の各クライアントの転送を完全に機能させるか、完全にロールバックする(つまり、各転送を独自のトランザクションに配置する)ことができます。

ただし、そのような転送の「トップレベル」の下にあるカーソルを使用したいと思った状況は考えられません(たとえば、次に転送するクライアントを選択するなど)。

于 2011-07-29T19:10:44.667 に答える
2

多くの場合、動的SQLを作成するときは、カーソルを使用する必要があります。データベース内のすべてのテーブルを検索して、異なるフィールドで同じ値を検索するスクリプトを想像してみてください。最善の解決策はカーソルです。問題が発生した質問はここにありますこの場合、ループせずにEXECまたはsp_executeSQLを使用するにはどうすればよいですか?誰かがカーソルなしでそれをよりよく解決できれば、私は本当に感銘を受けます。

于 2011-07-29T19:25:41.310 に答える