SQL Server内でカーソルとループをあらゆるコストで回避する傾向があることは知っていますが、手続き型クエリが絶対に必要で、セットベースのクエリでは結果が得られない状況は何ですか?
2つの違いを理解していますが、カーソルを使用する必要がある状況に至ったことがありません。そのような状況があるのだろうか。
SQL Server内でカーソルとループをあらゆるコストで回避する傾向があることは知っていますが、手続き型クエリが絶対に必要で、セットベースのクエリでは結果が得られない状況は何ですか?
2つの違いを理解していますが、カーソルを使用する必要がある状況に至ったことがありません。そのような状況があるのだろうか。
回答:
私の経験では、手続き型/反復型のアプローチが正当化されることが何度かありました。
このSOの質問のように500個の誤って入力された列があるテーブルで、プログラムでデータ型を実数から10進数に変更したい場合、DDLでは1つのステートメントで複数の列を変更できないため、カーソルは適切なアプローチです。
SQL Server MVPディープダイブの本をお持ちの場合、Hugo Kornelisによる第4章「セットベースの反復:3番目の代替案」には、カーソル/セットベースの操作を組み合わせた優れた使用例がいくつかあります。この章の著者が参照する2つの古典的な問題は、積算合計とビンパッキングです。
セットベースの反復アプローチを使用して、最後のジョブで受け継いだ設計が不十分なプロセスに成功しました。つまり、年に1度は5千万から7千万行を更新する必要があり、1つのセットで更新しようとすると、ログが破壊されるというプロセスがありました。更新をN行の小さなバッチにチャンク化することにより、ログを維持し、実際にメトリックトンより多くのディスクスペースを割り当てたときよりも前の年よりも速く完了しました。
セットベースで実行できないこと。
もちろん明らかな出血。ただし、「セットベースではない」と手続き型ソリューションを使用している人々は、セットを理解していないか、セットベースのコードでそれを行う方法がわからないため、違いがあることに注意してください。
手続き型コードの1つの例は、行ごとに内容が異なるメールを行ごとに送信することです。
DBAが使用するSQLコードの多くは手続き型です。たとえば、データベースとテーブルをループ(CURSORまたはWHILE:違いなし)して、インデックスを再構築し、統計を更新します。
一部のSQL構成では、セットのコンテキストで行ごとの処理を許可しています。たとえば、次のようにCROSS APPLYを実行します。各FKに対してSELECT TOP 5行(ただし、ROW_NUMBER()ソリューションにも注意)
編集:@billinkcの答えを拡張しています...
CROSS APPLYは、「単一行API」を持つUDFでのセットベースの操作を許可します
SQL Serverについて質問しているのは承知していますが、Oracleの世界では(以前は)一時テーブルのコストが非常に高かったため、カーソルベースのプロシージャとトリガーは、サーバーにとってより高速で低コストでした。SQL Serverでは、カーソルは一時テーブルよりもはるかに高コストでしたので、カーソルベースのコードの作成は推奨されませんでした。これらの不一致は過去10年間で解消されたと確信しています。
これらの状況に対処するために、ほとんどの人はビジネスロジックをデータベースに入れないようにする一般的なルールを持っています。完全に常にそうすることができれば、T-SQLでもPL / SQLでも手続き型ロジックを使用する理由は何もありません。リレーショナルデータベースは、セットベースのロジックに優れています。最新のプログラミング言語のほとんどは、手続き型ロジックに優れています。それぞれが得意な分野に使用するのが最善です。
私が使用したいくつかの監査トリガーには、何をチェックする必要があるか、どこを更新/ログする必要があるかについて、かなり複雑なルールがありました。一部はレポートシステムとトランザクションシステムの同期を維持するためのものでした(それは私の選択ではありませんでしたが、そのようにしたかったのです)。一部はフォーミュラリーシステム用でした。フォーミュラリーは、医薬品のリストであり、各保険会社について、それらがカバーする/カバーしないものであり、drug_Xが処方された場合、保険でカバーされる代替品です。同じ保険会社の異なるグループポリシーが異なる薬の代金を支払うことも一般的でした。