2011-08-09 7 views
2

私はSQLでかなり新しいですが、私はより速く継承した既存のクエリをいかにして作り出すかを考えなければなりません。ここで一時テーブルを使用した高速SQLクエリですか?

は、そこにそれらのいずれかのWHERE句です:

@SearchFor nvarchar(200)   
,@SearchIn nvarchar(1024)  
,@SearchActivity int 

    -- stuff here I've left out --- 

WHERE 
    (-- filter for all queries -- 
      (FT_TBL.IsActive = 1) 
     AND (FT_TBL.IsPro = 1) 
     AND (
      (FT_TBL.DatePaidUpTo >= @CurrentTime) 
      OR (
       (FT_TBL.IsFromPaidBusinessDB = 1) 
       AND (FT_TBL.DatePaidUpTo IS NULL) 
      ) 
     ) 
     AND (aspnet_Membership.IsApproved = 1) 
    )  
    AND (-- filter if user fills in 'searchfor' box -- 
      (@SearchFor IS NULL) 
     OR (FT_TBL.CompanyName like '%' + @SearchFor + '%') 
     OR (aspnet_Users.UserName like '%' + @SearchFor + '%') 
     OR (Activities.Activity like '%' + @SearchFor + '%') 
    ) 
    AND (-- filter if user fills in 'searchIn' box -- 
      (@SearchIn IS NULL) 
     OR (a1.City LIKE '%' + @SearchIn + '%') 
     OR (a1.Region LIKE '%' + @SearchIn + '%') 
     OR (a1.Postcode LIKE '%' + @SearchIn + '%') 
     OR (Country.Name LIKE '%' + @SearchIn + '%') 
    ) 
    AND (-- filter by activity -- 
      (@SearchActivity IS NULL) 
     OR (@SearchActivity = Activities.ActivityID) 
    ) 

    AND NOT EXISTS (Select a2.AddressId, a2.UserId 
      from Addresses a2 
      where a2.userid = a1.UserId 
      and a2.addressid < a1.addressid 
    ) 

SearchInSearchFor、およびSearchActivityそれは、検索結果をフィルタリングするために通過できるという三つのフィールドです。考え方は、これらのそれぞれについて 'null'が渡された場合、検索結果の唯一の制約はWHERE句の最初のブロックに由来するということです。これらの3つのフィールドのいずれかがNULLでない場合、結果はその行のロケーション、名前、またはカテゴリに基づいてさらに制約されます。最後のブロックは少しトリックです。ユーザーはいくつかのアドレスを付けることができますが、各ユーザーには1つの行しか返されません。したがって、このブロックはIDが最も小さいアドレスを選択します。

このクエリは非常にゆっくり実行されます。私たちのハードウェアがアンダーパールであることもありますが、このプロシージャは十分効率的ではないためです。私は、SQLをどのように同時に動作させるのかを学ぶ際に、難しい問題を解決する方法を試しています。

私が持っていたアイデアの1つは、2段階で検索を実行することでした。たとえば、最初にWHERE句の最初のブロックのみを使用してクエリを実行し、次に結果テーブルに2番目のクエリを実行します。残りのブロックはWHERE節にあります。最初のブロックがテーブル内の多くの行を除外するので、これが役立つと思いました。

誰かがこのクエリを改善する良い方法を提案できますか?また、どのツールがクエリの効率をテストするのに最適ですか?同じ入力であっても実行時間が大きく変動することがあります。

+2

参考までに、あなたの 'LIKE'比較のどれもインデックスを使うことができないので、私はそれだけで**テーブルスキャン**を最小にしています** – JNK

+0

私はそれをやることができません他の方法 - ユーザーのテキスト入力に基づく検索。 – Oliver

+0

フルテキストインデックスを調べる – JNK

答えて

4

いくつかのポイント:すべての

  1. まず:実行計画を読んで学ぼう!最後のクエリをSSMSに貼り付け、SQL Serverにクエリの実行計画を表示させます。次に、最も多くの時間を費やす部分を探します(通常table scansclustered index scans)。これらはあなたがよりよく見えるべきポイントです。

  2. インデックスを使用できるようにクエリを最適化します。つまり、クエリ内のLIKE '%value%'部分を取り除きます。可能であれば、ユーザーにbegins withまたはexactの一致検索を行うように強制します。 contains構文では、テーブルに10k行が始まるとパフォーマンスの問題が発生します。

  3. 最後に落ちたのはNOT EXISTSブロックなので非常に高額です。結果表示にフィルタリングを行います。

  4. 必要に応じて、列にインデックスを追加します。 SQL Serverのバージョンによっては、欠落しているインデックスに関するヒントも表示されることがあります。

  5. クエリのボトルネックを本当に特定できない場合は、クエリの一部を取り除き、パフォーマンスと実行計画の変更に影響を与えます。

+0

ご協力いただきありがとうございます。 'LIKE '%value%'で笑顔をすることはできませんが、' NOT EXISTS'ブロックについて何かできます。実行計画がどのように機能するかを調べてみましょう。 – Oliver

2

私が見る限り、クエリにはWHERE条件が多く含まれる一般的な問題があります。 SQLServerは、検索に必要な列が多すぎる可能性があるため、クエリの適切な実行計画を見つけることができない場合があります。

また、 '%' + searchWord + '%'を含むLIKEは、必要な値を返すことができますが、効果的にIndexusageを先取りします。先頭の '%'はすべてを検索する必要があるためです。おそらく最もよく使われるshearchのシナリオを集めて最適化することができます(統計の収集、実行計画の見直し、これらのインデックスの作成など)。すべてを行う1つのクエリを持つことは常に最適化するのが難しいです。

ClusteredIndexをColumnに配置すると、テーブルカーンを避けるために結果を最大限に制限することができます(Dateなど)。

+0

ご意見ありがとうございます。このクエリの要件のために、そのような 'LIKE'の使用を避けることは困難です。私はいくつかの他のフィールドにインデックスを置くことを試みるでしょう。 – Oliver

1

クエリの作成方法は天気に影響し、インデックスを使用できるかどうかを理解する必要があります。これらのテクニックを読んで、学習し、使用することによって:Dynamic Search Conditions in T-SQL by Erland Sommarskogあなたはインデックスを使用するより良い機会が得られます(より速いクエリの結果)。

あなたはSQの最新verison実行されている場合:Server 2008には、これは(前のリンクに記載された技術である)迅速な答えです: How can I use optional parameters in a T-SQL stored procedure?

0

私は不可避的に遅いとの問題に直面していますクエリでは、クエリを2つの段階に分割します。

ステージ1はレコードIDのリストを@table変数に取り込み、インデックス付きで高速なWHERE句のみを適用します。

ステージ2は、完全に多フィールドの多数結合クエリに対して@tableを結合します。ここで、LIKE句やUDF呼び出しなどの低速フィルタを適用できます。ステージ2は、小さなレコードセットに対してのみ低速フィルタを適用するため、高速です。

関連する問題