SQL Server sproc クエリの最適化
-
20-09-2019 - |
質問
次のようなレポートのデータを生成するアプリケーションがあります。
age < 30 | age >=30 | asian | hispanic
-----------------------------------------------------------------
clients in prog A | | |
-----------------------------------------------------------------
clients in prog B | | |
-----------------------------------------------------------------
number clients | | |
-----------------------------------------------------------------
number children | | |
クエリは非常に長い場合があるため、最適化したいと考えています。
サーバー上でクエリ アナライザーを実行する権限がありません (クエリ アナライザーの方が良い場合が多いと読みました) ない その提案を使用してください)。最長の sproc の実行には最大 35 秒かかります。
読んでみると、高度なクエリ最適化のために避けるべきことは次のとおりです。
- 選択する *
- 存在します
- 明確な
- カーソル
- 持っている
当面のタスクに関していくつか質問があります。
- Select * を Select ColA、colB ... に変更すると、どれだけの違いが見られるでしょうか。?本当に苦労する価値があるのでしょうか?
- 存在する場合はどうすれば最適化できますか( ...)?if( Select Count(query ) > 0 ) は適切な最適化ですか?
- 本当に戻るつもりなら 全て テーブル内の列の場合、Select * を使用しても大丈夫ですか?
これらのクエリは非常に長くてひどいため投稿したくありませんが、他にどのような提案ができるでしょうか?脳とサーバーの両方の負担を軽減するために、可能な限り再利用可能な関数と一時テーブルを使用するようにしています。
解決
1)Select *をSelectcolA、colB...に変更することによって、どの程度の違いが見られますか??本当に苦労する価値があるのでしょうか?
これは非常に大きな違いを生む可能性があります。一般的には、必要なフィールドを指定し、そのフィールドのみを指定することをお勧めします。つまりそのうちの 2 つだけが必要なときに SELECT * を実行して 50 個のフィールドを返し、それらの 2 つのフィールドが適切なインデックスに含まれている場合、残りのデータをインデックスから検索することなく、インデックスからすべてのデータを提供できます。データページ。したがって、これははるかに優れています。
2)存在する場合はどうすれば最適化できますか( ...)?if( Select Count(query ) > 0 ) は適切な最適化ですか?
いや...SELECT COUNT() の方がひどいです。存在します は 最初に一致するレコードが見つかるとすぐにチェックを停止するように最適化されているため、この種の処理を行う最もパフォーマンスの高い方法です。一方、 COUNT() はすべてが見つかるまで続行されますが、これは不必要です。カーソルを使用する場合は、「EXISTS」を分類するつもりはまったくありません。
3) 本当にテーブル内のすべての列を返す場合、Select * を使用しても問題ありませんか?
まあ、本当にすべてが欲しいのであれば、それほど問題ではありません。これは、将来さらに列を追加する場合、それらの列も返されるようにすることを前提としています。これにより、既存のコードが突然変更された場合に破損する可能性があります。
他のヒント
は、クエリを投稿することができます。
あなたが任意のコードが表示されていないため、ここではいくつかのポインタであります
が存在し、一般的には、より速く、カウント(*)、その後で返します、それはそれは、結果セットの最後に到達するまでカウントが()続けるマッチを見つけた瞬間に存在するため、
を選択col1の列が非クラスタ化インデックスである場合、ベーステーブル/クラスタ化インデックスにも触れることなくなり、その後、これは今、あなたは、インデックスの列が含まれていることがさらに事実であるので、col2が*選択よりも優れています。あなたが必要な列だけを返す場合は、より少ない帯域幅を使用します。
私は本当に、テーブルのすべての列を返すつもりだ場合は、、それは*選択して使用しても大丈夫でしょうか?
誰かが後でテーブルに4列を追加する場合は何?今、あなたはまた、これらの4つの列を返すことになる。
脳とサーバーの両方の負担を軽減するために、可能な限り再利用可能な関数と一時テーブルを使用するようにしています。
ユーザー定義関数のことを指していると仮定すると、それらは必ずしもパフォーマンスに良いとは限りません。脳への負担を軽減しようとすると、サーバーへの負担が増大するという犠牲が生じる可能性があります。純粋にスカラーのもの (つまり、値を取得し、それを操作して別の値を返すもの) は問題ありませんが、テーブルをスキャンするものは、通常、そのロジックがストアド プロシージャで直接使用されるとより高速に実行されます。たとえば、テーブル X で値 Y の出現をスキャンし、カウントを返す関数は、すべての値のカウントを一度に実行できる結合を含む SQL ステートメントよりも実行が遅くなります (呼び出しが繰り返されるため)。
関連するソーステーブルにインデックスがあるかどうか、およびそれらが使用されているかどうかも確認する必要があります。
あなたはそれが良い符号化であるので....しかし、あなたがそれを行う必要があり、COLUMN2、column1のを選択する場合に選択*から変更することから利益の多くを得ることはありません。誰かが将来の列の列の順序や数を変更した場合、それはあなたのレポートは、彼らが構築されている方法に応じて破損する場合があります。
どのように別のアプローチはどうですか?あなたは、テーブル上の非クラスタ化インデックスを追加することができるならば、私はそれに探してお勧めします。具体的には、あなたが存在サブクエリを見て、どこのセクションにある列に、索引を持っているかどうかを確認します。それがtrueを返した場合でも、毎回スキャンし、彼らは、あなたがテーブルにはfalseを返しますが存在するたびにスキャンことになるだろうとせず、あなたがテーブルまでやっていることができれば(それは価値がでている場所によって異なります)。非クラスタ化インデックスは、サブクエリがすばやくテーブル内の任意の結果を見つけることができるようになります。時には、あなたは非効率的なクエリを使用する必要がありますが、あなたはインデックスを通して、あなたのテーブル構造を最適化することができれば、それはあなたの速度への影響のあまりになります。
あなたは、サブクエリが存在するためにまた、今までそれはあなたが最も1つの結果であります場合ですか?そうなら、あなたは、テーブルに参加し、左をやってみたいことがあります。あなたの参加の左右の列セットの両方にインデックスをしませんが、あなたが行う場合は、基本的には右手のテーブル1時間スキャンの代わりに、一度行あたりと同じように、それはかなり役立つはずあれば、おそらく助けにはなりませんます。
カウントするための、最も効果的な形態は、テーブルからの選択数(1)です。 (あるいは、0または123または任意の単純な一定値)。
あなたも、管理のために...、フィールド1、フィールド2を選択するように変更する必要があります。 SELECT *が遅くなり、以降あなたは問題(それらの以上)コード、ビューまたはテーブルの変化に遭遇することがあります。