web-dev-qa-db-ja.com

SQL Serverでの積極的なスプール操作を回避する方法

SELECT INTOステートメントを頻繁に使用するストアドプロシージャを含むETLプロセスがあります(ログに記録される量が少ないため、ログトラフィックが少なくなるため高速になります)。 1つの特定のストアドストアドプロシージャで行われる作業のバッチのうち、最も高価な操作のいくつかは、クエリ結果を単にバッファリングし、作成中のテーブルにコピーするように見える熱心なスプールです。

熱心なスプール に関するMSDNドキュメントは非常にまばらです。誰がこれらが本当に必要であるか(そしてどのような状況下で)より深い洞察を持っていますか?私は理にかなっているかもしれないし、そうでないかもしれないいくつかの理論を持っていますが、クエリからこれらを除去することに成功していません。

.sqlplanファイルは非常に大きい(160kb)ので、フォーラムに直接投稿することはおそらく合理的ではないと思います。

そのため、特定の答えを受け入れられる可能性のあるいくつかの理論があります。

  • クエリは、書式設定された日付の解析など、データ変換にいくつかのUDFを使用します。このデータ変換では、構築する前に賢明なタイプ(たとえば、varcharの長さ)をテーブルに割り当てるために、積極的なスプールを使用する必要がありますか?
  • 上記の質問の延長として、誰かがクエリでこの操作を駆動するかしないのかについて、より深い見解を持っていますか?

スプーリングについての私の理解は、それがあなたの実行計画のちょっとしたニシンだということです。はい、クエリコストの大部分を占めますが、実際には、コストのかかる再スキャンを回避できるように、SQL Serverが自動的に行う最適化です。スプーリングを回避した場合、それが置かれている実行ツリーのコストは上昇し、ほぼ確実にクエリ全体のコストが増加します。特にSQLコードを見ずに、データベースのクエリオプティマイザーが実行をそのように解析する原因となる特定の洞察はありませんが、おそらくその動作を信頼する方が良いでしょう。

ただし、それは、実行している内容とソースデータの揮発性に応じて、実行計画を最適化できないという意味ではありません。 SELECT INTO、実行計画にスプール項目が表示されることがよくありますが、これは読み取り分離に関連している可能性があります。特定の状況に適している場合は、トランザクションの分離レベルを低コストに下げるか、NOLOCKヒントを使用するか、またはその両方を試してみてください。複雑なパフォーマンスクリティカルなクエリでは、NOLOCKがデータに安全で適切であれば、何らかの理由がないように思われる場合でもクエリの実行速度を大幅に向上できることがわかりました。

この状況で、READ UNCOMMITTEDまたはNOLOCKヒントを使用すると、一部のスプールを削除できる場合があります。 (明らかに、一貫性のない状態に陥る可能性がある場合は、これを行いたくありませんが、すべてのデータ分離要件は異なります)。 TOP演算子とOR演算子は時々スプールを引き起こす可能性がありますが、ETLプロセスでこれらのいずれかを実行しているとは思わない...

あなたはあなたのUDFが犯人である可能性があると言っているのは正しいです。各UDFを一度だけ使用する場合、パフォーマンスを大幅に向上させるかどうかを確認するために、それらをインラインに配置することは興味深い実験になります。 (そして、クエリでインラインで記述する方法がわからない場合は、おそらくスプールを引き起こしている可能性があります)。

最後に確認することの1つは、並べ替えが可能な結合を行う場合は、ヒントを使用して、最も選択的な順序であることがわかっている順序で結合順序を強制的に実行することです。それは少しの範囲ですが、すでに最適化にこだわっている場合、それを試しても害はありません。

30
Grank