2

特にテーブルが大きくなったり、多くの行を更新する必要がある場合は、テーブルのセットベースの処理が常に RBAR よりも優先されるべきであるというのが従来の知恵です。

しかし、それは常に成り立ちますか?私はさまざまなハードウェアで、同じワークロードをより小さなチャンクに分割すると直線的に増加する一方で、セットベースの処理では時間消費が指数関数的に増加する状況をかなり多く経験しました。

完全に間違っていることが証明されるのは興味深いことだと思います-明らかな何かが欠けている場合-または、そうでない場合は、ワークロードを分割することがいつ努力する価値があるかを知ることは非常に良いでしょう. その後、どの指標を使用するかを決定するのに役立つ指標を特定します。個人的には、次のコンポーネントが興味深いと期待しています。

  • ワークロードのサイズ
  • ログファイルのサイズと増大
  • RAMの量
  • ディスクシステムの速度

他の?CPU/CPU コアの数?

例 1: 1,200 万行のテーブルがあり、各行の 1 つまたは 2 つのフィールドを別のテーブルのデータで更新する必要があります。これを 1 回の簡単な更新で行うと、テスト ボックスで 30 分ほどかかります。しかし、これを 12 個のチャンクに分割すると、約 24 分で完了します。

WHERE <key> BETWEEN 0 AND 1000000
WHERE <key> BETWEEN 1000000 AND 2000000
...

例 2: 実質的にすべての行に対していくつかの計算を行う必要がある 2 億行以上のテーブルです。フルセットをオールインワンで実行すると、私のボックスは 3 日間稼働し、それでも完了しません。まったく同じ SQL を実行する単純な C# を作成し、トランザクション サイズを一度に 10 万行に制限するために WHERE 句を追加すると、約 14 時間で完了します。

記録のために:私の結果は、同じデータベースからのもので、同じ物理ハードウェア上にあり、統計が更新され、インデックスに変更はなく、単純な復旧モデルなどがあります。

いいえ、「真の」RBAR を試したことはありませんが、実際にどれくらいの時間がかかるかを確認するためだけに試したほうがよいでしょう。

4

1 に答える 1

3

いいえ、セットベースの方が常に速いというルールはありません。カーソルがあるのには理由があります (そして、while ループやその他の種類のループが実際にはカーソルとまったく異なると信じ込まないでください)。Itzik Ben-Gan は、特に実行中の合計の問題で、カーソルがはるかに優れているいくつかのケースを示しています。また、1,200 万行を更新しようとしていて、メモリの制約、ログの使用、またはその他の理由により、SQL が tempdb にスピルしたり、解決したりすることなく単一の操作として処理するには多すぎると説明する場合もあります。より最適な計画を十分に迅速に取得できないため、早期終了による次善の計画。

カーソルが非難される理由の 1 つは、人々が怠け者で次のように言うからです。

DECLARE c CURSOR FOR SELECT ...

ほとんどの場合、次のように言う必要があります。

DECLARE c CURSOR 
    LOCAL FORWARD_ONLY STATIC READ_ONLY 
    FOR SELECT ...

これは、これらの余分なキーワードがさまざまな理由でカーソルをより効率的にするためです。ドキュメントに基づいて、これらのオプションのいくつかは冗長であると予想されますが、私のテストではそうではありません。詳細については、私のこのブログ投稿と、仲間の SQL Server MVP Hugo Kornelis によるこのブログ投稿を参照してください。

とはいえ、ほとんどの場合、最善の策はセットベース(または、少なくとも上記のように分厚いセットベース)になります。しかし、1 回限りの管理タスク (1,200 万行の更新であることを願っています) の場合、適切な計画を生成する最適なクエリを作成するために多くの労力を費やすよりも、カーソルを記述するだけの方が簡単/効率的です。アプリケーションの範囲内で通常の操作として多く実行されるクエリについては、セットベースとして最適化を試みる価値があります (カーソルが残る可能性があることに注意してください)。

于 2011-09-03T17:17:41.213 に答える