2009-07-08 8 views
1

Slow Exists Checkの続編です。アレックスの提案はうまくいき、コードの繰り返しを避けることができますが、まだ2番目の問題に終わります。以下の例を考えてみましょう(AlexKuznetsovより)。その中には、1つの制約を扱う2つの枝があります。 2つのオプションの制約がある場合、私は4つのブランチで終わるだろう。基本的に、枝の数は制約の数とともに指数関数的に増加する。Where句での複数のオプション制約の効率的な処理

一方、複数値テーブル値関数を使用したり、一時テーブルを使用したりすると、SQLクエリオプティマイザが私を支援できないため、処理が遅くなります。私は動的SQLをやや不信に思っています(また、それも遅いと聞いてきました)。

多くのif文を追加しなくても、制約を追加する方法の提案はありますか?

注:私はこれまでにx is null or inpo = @inpoを連鎖させてみましたが、これは非常に遅いです。 inpo = @inpoテストはある種の索引付けブラックマジックで処理できますが、無効テストはテーブル内のすべての行について評価されることになります。

IF @inpo IS NULL BEGIN 
    SELECT a,b,c 
    FROM dbo.ReuseMyQuery(@i1) 
    ORDER BY c; 
END ELSE BEGIN 
    SELECT a,b,c 
    FROM dbo.ReuseMyQuery(@i1) 
    WHERE inpo = @inpo 
    ORDER BY c; 
END 

バリエーション2:2つの制約:

IF @inpo IS NULL BEGIN  
    IF @inpo2 IS NULL BEGIN 
     SELECT a,b,c 
     FROM dbo.ReuseMyQuery(@i1) 
     ORDER BY c; 
    END ELSE BEGIN 
     SELECT a,b,c 
     FROM dbo.ReuseMyQuery(@i1) 
     WHERE inpo2 = @inpo2 
     ORDER BY c; 
    END 
END ELSE BEGIN 
    IF @inpo2 IS NULL BEGIN 
     SELECT a,b,c 
     FROM dbo.ReuseMyQuery(@i1) 
     WHERE inpo = @inpo 
     ORDER BY c; 
    END ELSE BEGIN 
     SELECT a,b,c 
     FROM dbo.ReuseMyQuery(@i1) 
     WHERE inpo = @inpo AND 
       inpo2 = @inpo2 
     ORDER BY c; 
    END 
END 

答えて

0
Select blah from foo  
Where (@inpo1 is null or @inpo1 = inpo1) 
and (@inpo2 is null or @inpo2 = inpo2) 

どうやらこれは遅すぎます。面白い。

コード生成について考えましたか?重複の多い長いクエリは、直接保守する必要がある場合にのみ問題になります。

+0

Slow Existsチェックで述べたように、その解決策は遅いです。 – Brian

0

ここにおおよその例があります。 WHERE句のLIKE文を変更するには、クエリに "starts with"または "contains"または完全一致が必要かどうかを指定します。

CREATE PROCEDURE dbo.test 
@name  AS VARCHAR(50) = NULL, 
@address1  AS VARCHAR(50) = NULL, 
@address2  AS VARCHAR(50) = NULL, 
@city  AS VARCHAR(50) = NULL, 
@state  AS VARCHAR(50) = NULL, 
@zip_code  AS VARCHAR(50) = NULL 
AS 

BEGIN 

SELECT [name], 
      address1, 
      address2, 
      city, 
      state, 
      zip_code 
FROM my_table 
WHERE ([name] LIKE @name + '%' OR @name IS NULL) 
      AND (address1 LIKE @address1 + '%' OR @address1 IS NULL) 
      AND (address2 LIKE @address2 + '%' OR @address2 IS NULL) 
      AND (city LIKE @city + '%' OR @city IS NULL) 
      AND (state LIKE @state + '%' OR @state IS NULL) 
      AND (zip_code LIKE @zip_code + '%' OR @zip_code IS NULL) 
ORDER BY [name] 
END 
GO 
+0

私は以前これを試しました(最初の質問で言及しました)。それは遅いです。 – Brian

0

は、私はあなたの質問は、純粋に学術的かもしれ実現していますが、現実の世界のユースケースを持っている場合にのみ、最も一般的なシナリオ用に最適化されたクエリを提供すると考えられてきましたか? Erlandの記事で説明したように、私はsp_executesqlを使用するような場合には

+0

私は解決策としてそれについて考えましたが、私は理想ではなく選択肢がなければ使用するものと考えています。 – Brian

1

:動的SQLが使用されるたびに、不足している権限が問題である可能性があり、私はユニットテストのための実際のネットワークのアカウントを持ってUsing sp_executesql 、私は実際の役割にそのアカウントを追加ここで説明するように、動的SQLをテストするたびに、その実際のアカウントで偽装します。Database Unit Testing: Impersonation

+0

ええ、それは私が使い終わったものです。 – Brian

関連する問題