2009-08-18 17 views
8

私は約100万レコードのテーブルを持っています(SQL Server 2008 Webを実行しています)。私は商品コードと商品説明にマッチする検索ルーチンを持っています。 しかし、状況によっては非常に遅いです。以下は(カットダウン)SQL文:このSQL文はなぜ非常に遅いのですか?

WITH AllProducts AS (
    SELECT  p.*, Row_Number() OVER (ORDER BY ProductId) AS RowNumber 
    FROM  Product AS p 
    WHERE p.IsEnabled=1 AND 
    (
     p.BaseSku = 'KPK-3020QWC-C' -- this on its own is fast 
     OR 
     CONTAINS(p.FreeTextStrings, '"KPK-3020QWC*"') -- and this on its own is fast, but not both 
    ) 
) SELECT * FROM AllProducts   
    WHERE RowNumber BETWEEN 1 AND 20; 

注私はちょうど[p.BaseSku = 'KPK-3020QWC-C']または[CONTAINS(p.FreeTextStrings、「「KPK-3020QWCに比較した場合には* "))]を個別に(ただし両方ではなく)瞬時に実行します。私はそれらを一緒に比較すると、時間がかかります(数分)。

IsEnabledとBaseSkuにはインデックスが付けられ、FreeTextStringsはFTSインデックスに登録されています。

私はこれがうまくいきました。

誰もがこれについてどのような光を放ち、いくつかの解決策を提案できますか?

実行計画ファイルはここにあります:http://wiki.webgear.co.nz/GetFile.aspx?File=Temp%5cSearch%20Test.sqlplan.zip

+0

SQL Serverから実行計画を表示できますか? –

+0

これらの問題は、SQL 2005をSQL 2008にアップグレードした後に発生し始めました。 – Muxa

答えて

10

orは、SQL Server上で悪名高い遅いです。それは悪化しています。

unionで2つのクエリにそれを分割してみてください。

WITH AllProducts AS (
    select *, Row_Number() OVER (ORDER BY ProductId) AS RowNumber 
    from (
    SELECT  p.* 
    FROM  Product AS p 
    WHERE p.IsEnabled=1 AND 
     p.BaseSku = 'KPK-3020QWC-C' 
    UNION 
    SELECT  p.* 
    FROM  Product AS p 
    WHERE p.IsEnabled=1 AND 
     CONTAINS(p.FreeTextStrings, '"KPK-3020QWC*"') 
) 
) SELECT * FROM AllProducts   
    WHERE RowNumber BETWEEN 1 AND 20; 
+1

BaseSkuとFreeTextStringsの両方にインデックスがある場合でも、「or」は製品テーブルでテーブルスキャンを引き起こす可能性が最も高いです... seek + index scan ...(その2つの列をカバーするインデックスがあると仮定して) – KristoferA

+0

私はそれを試みましたが、実際に大きな改善が見られました。私は完全なSQLステートメントでこのテクニックを試してみます。 – Muxa

+0

うん、これで解決しました。しかし、私は、同じステートメントがSQL 2005で非常に速く働いていて、SQL 2008で遅く動作していることは非常に奇妙だと思います。これが次のサービスパックで対処されるかもしれませんか? – Muxa

1

これがうまく動作するようです:

WITH AllProducts AS (
    SELECT  p.*, Row_Number() OVER (ORDER BY ProductId) AS RowNumber 
    FROM  Product AS p 
    WHERE p.IsEnabled=1 AND 
    (
     CONTAINS(p.BaseSku, 'KPK-3020QWC-C') /* instead of p.BaseSku = 'KPK-3020QWC-C' */ 
     OR 
     CONTAINS(p.FreeTextStrings, '"KPK-3020QWC*"') 
    ) 
) SELECT * FROM AllProducts   
    WHERE RowNumber BETWEEN 1 AND 20; 

(私はすでにBaseSku FTS-インデックス付けた)

0

Make sure all necessary indexes are in place.私は私のクエリの1つにor句と同じ問題があり、INCLUDE列でNONCLUSTERED INDEXを作成してパフォーマンスを修正しました。さらにテスト後

、それはが列に実際にパフォーマンス上の問題を固定インデックスの一部をINCLUDEでした。ここで私が問題とどのようにそれを修正するのかを決定するためにやったことだ:

あなたが欠落しているインデックスを作成するのに役立つ実行計画を使用してください:インデックスなし

それが持っている必要がある場合、クエリが2+分を取っていました数ミリ秒で走った。だから私はSSMSのor句の有無にかかわらずクエリの実行計画を比較しました。実行計画の理解が不足しているために、私は何をする必要があるのか​​分かりませんでした。

ただし、実行計画を緑色のテキストの上に表示すると、SSMSによって非クラスタ化インデックスの作成が指示されることがあります。うーん...ショットに値する。だから私はインデックスを作成し、問題を解決しました! "CREATE INDEX"クエリを右クリックし、 "Missing Index Details ..."を選択することができます。これにより、実行するための完全なクエリを含む新しいタブが開きます。ちょうど名前をつけてください。

関連する問題