この「ひざまずくパフォーマンスチューニング」シリーズの続きでは、一時テーブルの使用でよくある4つの問題について説明します。これらの問題のいずれかがワークロードを損なう可能性があるため、環境について知って探す価値があります。
問題1:不要な場所で一時テーブルを使用する
https://www.flickr。 com / photos / tea_time / 3890677277 /一時テーブルにはさまざまな用途があります(おそらく最も一般的なのは、後で使用するために中間結果セットを保存することです)が、一時テーブルをクエリに導入すると、データの流れが中断されることを覚えておく必要があります。クエリプロセッサ。
中間結果セットを生成するクエリ(プロデューサーと呼びましょう)があり、それがtempdbの一時テーブルに格納されてから、次のクエリ(呼び出しましょう)があるため、一時テーブルの作成をハードストップと考えてください。コンシューマー)は、一時テーブルからデータを再度読み取る必要があります。
一時テーブルが完全に削除されると、ワークロードの一部のパフォーマンスが実際に向上することがよくあります。そのため、データは、tempdbに永続化することなく、クエリのプロデューサー部分からコンシューマー部分に流れます。クエリオプティマイザは、より最適な全体的な計画を作成できます。
あなたは今、「それで、物事が遅くなるのに、なぜ誰かが一時的なテーブルを使うのだろうか」と考えているかもしれません。 –そして当然そうです!そのような場合、一時テーブルの使用が開発チームで制度化されていることがわかりました。何年も前に一時テーブルを使用するとパフォーマンスが向上することがわかったため、一時テーブルがデフォルトの設計選択になりました。
これを変更するのは難しい場合があります。特に、一時テーブルを常に使用する必要があると確信している上級開発者またはマネージャーがいる場合はそうです。簡単な方法は、高価なクエリ(たとえば、実行時間の長いクエリ、または1秒間に何度も実行されるクエリ)を選択し、1つ以上の一時テーブルを削除して、それらがないとパフォーマンスが向上するかどうかを確認することです。もしそうなら、非妥協者を示すためのあなたの証拠があります!
問題2:一時テーブルにデータを入力する際のフィルタリングの欠如
一時テーブルを削除できない場合でも、一時テーブルにデータを入力するコードがソーステーブルから取得したデータを正しくフィルタリングしていることを確認することで、パフォーマンスを大幅に向上させることができる場合があります。
SELECT *
で始まるコードが一時テーブルに入力されているのを確認した回数を数え切れませんでした。 、いくつかの無制限の結合が含まれ、WHERE句がありません。その後、一時テーブルを使用する後のクエリでは、いくつかの列のみが使用され、行数を大幅に絞り込むためのWHERE句があります。
ストアドプロシージャの一時テーブルがメインデータベースから15年分のデータを集約し、その年のデータのみが使用されていた1つのケースを覚えています。これにより、tempdbがディスクボリュームのスペースを使い果たすまで繰り返し成長し、ストアドプロシージャが失敗していました。
一時テーブルにデータを入力するときは常に、必要なソーステーブルの列のみを使用し、必要な行のみを使用してください。つまり、フィルター述部を一時テーブルのデータにプッシュします。これにより、tempdbのスペースが節約されるだけでなく、ソーステーブルから不要なデータをコピーする必要がなくなるため、多くの時間が節約されます(また、最初にディスクからソースデータベースページを読み取る必要がなくなる可能性があります)。
>問題3:一時テーブルのインデックスが正しくない
通常のテーブルの場合と同様に、クエリのパフォーマンスを向上させるために、後のクエリコードで実際に使用されるインデックスのみを作成する必要があります。一時テーブルの列ごとに非クラスター化インデックスがあり、後のコードを分析せずに選択された単一列のインデックスがまったく役に立たない場合がたくさんあります。一時テーブルにデータを入力するときに、役に立たない非クラスター化インデックスとフィルタリングの欠如を組み合わせると、tempdbの膨大な肥大化のレシピが得られます。
また、一般に、テーブルにデータが入力された後、インデックスを作成する方が高速です。これにより、インデックスに正確な統計が含まれるという追加のボーナスが得られます。これにより、クエリオプティマイザが正確なカーディナリティ推定を実行できるため、クエリがさらに役立ちます。
使用されていない非クラスター化インデックスが多数あると、ディスクスペースだけでなく、それらの作成に必要な時間も浪費されます。これが頻繁に実行されるコードにある場合、コードを実行するたびに作成されるこれらの不要なインデックスを削除すると、全体的なパフォーマンスに大きな影響を与える可能性があります。
問題4:tempdbラッチの競合
一時的なテーブルの使用にまでさかのぼることができる、tempdbにラッチのボトルネックがあることは非常に一般的です。一時テーブルを作成および削除するコードを実行している同時接続が多数ある場合、メモリ内のデータベースの割り当てビットマップへのアクセスが重大なボトルネックになる可能性があります。
これは、一度に1つのスレッドのみが割り当てビットマップを変更して、(一時テーブルからの)ページを割り当て済みまたは割り当て解除済みとしてマークできるため、他のすべてのスレッドが待機する必要があり、ワークロードのスループットが低下するためです。 SQL Server 2005以降、一時テーブルキャッシュがありますが、それほど大きくはなく、一時テーブルをキャッシュできるタイミングには制限があります(たとえば、サイズが8MB未満の場合のみ)。
この問題を回避する従来の方法は、トレースフラグ1118と複数のtempdbデータファイルを使用することでした(詳細については、このブログ投稿を参照してください)が、考慮すべきもう1つのことは、一時テーブルを完全に削除することです!
概要
一時テーブルは非常に便利ですが、非常に簡単で一般的に誤って使用されます。一時テーブルを使用してコードを記述(またはレビュー)するときは、次のことを考慮してください。
- この一時テーブルは本当に必要です ?
- 正しいフィルタリングを使用してテーブルに入力するコードです 一時テーブルのサイズを制限するには?
- インデックスはテーブルの作成後に作成されます (一般的に)そして使用されているインデックス 後のコードで?
Paul Whiteには、一時オブジェクトの使用法とキャッシュについてのすばらしい投稿がいくつかあります(こことここ)。私も読むことをお勧めします。
最後に、一時テーブルを使用しない場合は、テーブル変数、一般的なテーブル式、またはカーソル(これらはすべて、人々が「最適化」しようとする一般的な方法)に置き換えるだけではいけません。一時テーブル)–コードを(再)記述する最も効率的な方法を見つけます–「1つのサイズですべてに対応」という答えはありません。
次回まで、トラブルシューティングをお楽しみください!