0

次のようなレポートのデータを生成するアプリケーションがあります。

                    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 exists( ... ) を最適化するにはどうすればよいですか? if( Select Count(query ) > 0 ) は適切な最適化ですか?
  • 本当にテーブル内のすべての列を返す場合、 Select * を使用しても問題ありませんか?

これらのクエリは非常に長くてひどいので投稿したくありませんが、他にどのような提案を提供できますか? 再利用可能な関数と一時テーブルを可能な限り使用して、脳とサーバーの両方の負担を軽減しようとしています。

4

5 に答える 5

1

クエリを投稿できますか

コードを表示していないため、ここにいくつかのポインタがあります

一般に、existsはcount(*)よりも高速です。existsは一致を見つけた瞬間を返し、count()は結果セットの最後に到達するまで続行します。

select col1、col2はselect *よりも優れています。列が非クラスター化インデックスにある場合、ベーステーブル/クラスター化インデックスは変更されないため、インデックスに列が含まれているため、これはさらに当てはまります。また、必要な列のみを返す場合は、使用する帯域幅が少なくなります

テーブル内のすべての列を実際に返す場合は、Select *を使用しても大丈夫ですか?

後で誰かがテーブルに4つの列を追加した場合はどうなりますか?これで、これらの4つの列も返されます

于 2010-02-11T16:56:11.907 に答える
1

1)Select*をSelectcolA、colB ...に変更することで、どの程度の違いが見られますか?それは本当にトラブルの価値がありますか?
これは非常に大きな違いを生む可能性があります。通常は、必要なフィールドを指定し、それらのフィールドのみを指定することをお勧めします。つまり、SELECT *を実行して2つだけが必要なときに50のフィールドを返し、それらの2つのフィールドが適切なインデックスに含まれている場合、残りのデータを検索しなくても、インデックスからすべてのデータを提供できます。データページ。したがって、これははるかに優れています。

2)存在する場合はどうすれば最適化できますか(...)?if(Select Count(query)> 0)は良い最適化ですか?
いいえ...SELECTCOUNT()の方が悪いです。EXISTS、最初に一致するレコードが見つかるとすぐにチェックを停止するように最適化されているため、この種のことを行うための最もパフォーマンスの高い方法です。COUNT()は、不要なものがすべて見つかるまで続行します。悪いキャンプで「EXISTS」をカーソルで分類することはまったくありません。

3)テーブル内のすべての列を実際に返す場合は、Select *を使用しても大丈夫ですか?
まあ、あなたが本当にそれらすべてが欲しいなら、それはそれほど重要ではありません。これは、将来さらに列を追加する場合は、それらも返されるようにすることを前提としています。これにより、既存のコードが突然変更された場合に破損する可能性があります。

于 2010-02-11T16:57:27.160 に答える
1

再利用可能な関数と一時テーブルを可能な限り使用して、脳とサーバーの両方の負担を軽減しようとしています

ユーザー定義関数を意味すると仮定すると、それらは常にパフォーマンスに優れているとは限りません。脳への負担を軽減しようとすると、サーバーへの負担が増えるという代償を払うことになります。純粋にスカラーのもの (つまり、値を取り、それを操作して別の値を返すもの) は問題ありませんが、テーブルをスキャンするものは、そのロジックがストアド プロシージャで直接使用されている場合、通常はより高速に実行できます。例として、テーブル X をスキャンして値 Y の出現を探してカウントを返す関数は、一度にすべての値のカウントを実行できる結合を含む SQL ステートメントよりも実行が遅くなります (呼び出しが繰り返されるため)。

関連するソース テーブルにインデックスがあるかどうか、およびそれらが使用されているかどうかも確認する必要があります。

于 2010-02-11T17:10:51.853 に答える
0

Select * から Select column1,column2,... に変更してもあまりメリットはありませんが、適切なコーディングであるため変更する必要があります。将来、誰かが列の順序または列の数を変更した場合、作成方法によってはレポートが壊れる可能性があります。

別のアプローチはどうですか?テーブルに非クラスター化インデックスを追加できる場合は、それを調べることをお勧めします。具体的には、既存のサブクエリを見て、Where セクションにある列にインデックスがあるかどうかを確認します。そうでない場合は、exists が false を返すたびにテーブル スキャンを実行することになり、true を返す場合でも毎回テーブル スキャンを実行することになります (値がどこにあるかによって異なります)。非クラスター化インデックスにより、サブクエリはテーブル内の結果をすばやく見つけることができます。非効率的なクエリを使用しなければならない場合もありますが、インデックスを使用してテーブル構造を最適化できれば、速度への影響ははるかに少なくなります。

また、 Exists サブクエリの場合、結果が最大で 1 つになることはありますか? その場合は、テーブルへの左結合を試してみてください。結合の左側と右側の両方の列セットにインデックスを作成しない場合はおそらく役に立ちませんが、そうすると、基本的に行ごとに 1 回ではなく右側のテーブルを 1 回スキャンするので、かなり役立つはずです。 .

于 2010-02-11T17:04:43.303 に答える
0

カウントの場合、最も効果的な形式は SELECT Count(1) FROM table です。(または 0 または 123 または任意の単純な定数値)。

管理しやすくするためにも、SELECT field1、field2、.. に変更する必要があります。SELECT * は遅く、後でコード、ビュー、またはテーブル (またはそれらの多く) が変更されたときに問題が発生する可能性があります。

于 2010-02-11T17:11:07.770 に答える