2016-08-16 11 views
5

ユーザーが単一の閉期間(データウェアハウス表にアーカイブ)またはオープン期間(トランザクションのデータ)からデータを要求するかどうかによって、2つの異なるソースからデータを取得できるストアドプロシージャがあります。テーブル)。SQL IF ELSEパフォーマンスの問題

データウェアハウステーブルへの選択を制限するパラメータを渡すと(ELSE BEGIN ...コードをコメントアウトしない限り、プロシージャは結果を返すのに非常に時間がかかります)コードのELSE部分からのデータはありませんが、プロシージャの速度は低下しています。コードのELSE部分をコメントアウトすると、非常に高速です。

私はOPTION (RECOMPILE)を試しましたが、パラメータスニッフィングを避けるためにローカル変数を使用していますが、それは役に立ちません。これを回避する方法はありますか?私はELSE文を除外した場合、それは非常に高速に実行

IF @Year <> 0 AND @Period <> 0 AND (SELECT PerClosedTimestamp 
            FROM Period 
            WHERE 
             PerCompanyID = @CompanyID AND 
             PerYear = @Year AND 
             PerPeriod = @Period) IS NOT NULL 
BEGIN 
    SELECT 
     datawhse.column1, datawhse.column2, etc … 
    FROM  
     datawhse   
END 
ELSE 
BEGIN 
    SELECT 
     trantable.column1, trantable.column2, etc… 
    FROM  
     trantable  
END 

IF @Year <> 0 
    AND @Period <> 0 
    AND (SELECT PerClosedTimestamp 
     FROM Period 
     WHERE PerCompanyID = @CompanyID 
      AND PerYear = @Year 
      AND PerPeriod = @Period) IS NOT NULL 
BEGIN 
    SELECT datawhse.column1 
      ,datawhse.column2, etc … 
    FROM datawhse   
END 
+0

まだ回答がありませんが、興味深い関連記事(重複しない)です。http://dba.stackexchange.com/questions/9835/using-if-in-t-sql-weakens-or-breaks-execution-plan-キャッシング – scsimon

+0

"PerClosedTimestamp"の前にTOP 1を追加するか、EXISTSを使用するとどうなりますか?条件をIF Year = 0またはPeriod = 0に変更するか、(select ...)がnullの場合は2番目のブロックを実行し、最初の場合はELSEを実行します。また、 "WHERE Year = 0 or Period = 0"(条件を複製して)を2番目のブロックに入れてみてください。 – Anton

+2

遅くて速い実行のクエリプランを見るのはいいでしょう。 –

答えて

0

から直接@yearと@Periodです は、以下の遅い実行し、私はそれをやっているの例ですストアドプロシージャの入力?あなたのsprocの定義のように、あなたはこのように書くのですか?

create proc USP_name @Year int, @Period int as 
begin 
    ... 
end 

ローカル変数を使用してみることができます。このような多くの場合、私の経験によれば、ローカル変数は大いに役立ちます。コメントで述べたように

create proc USP_name @Year int, @Period int as 
begin 
    declare @Year_local int, @Period_local int 
    set @Year_local = @Year, @Period_local = @period 

    if @Year_local <> 0 AND @Period_local <> 0 AND ... 
    .... 
end 
+0

皆様のご意見ありがとうございます。データウェアハウステーブルまたはトランザクションテーブルのいずれかからデータを返す2つの別々の関数を作成しました。私はIF THEN ELSEステートメント内の関数から選択し、それは私の問題を解決したようです。 – gcresse

1

は、に決定的な答えは、なぜそれが遅いは常にクエリプランで発見されます。

この手順では、trantableのように見えますが、クエリオプティマイザはdatawhseのように偏っています。私は、少なくともクエリ・プランは比較方法を確認するために興味深いものになるだろう

SELECT 
    datawhse.column1, datawhse.column2, etc … 
FROM  
    datawhse 
WHERE @Year <> 0 AND @Period <> 0 AND (SELECT PerClosedTimestamp 
           FROM Period 
           WHERE 
            PerCompanyID = @CompanyID AND 
            PerYear = @Year AND 
            PerPeriod = @Period) IS NOT NULL 
UNION ALL 
SELECT 
    trantable.column1, trantable.column2, etc… 
FROM  
    trantable  
WHERE @Year = 0 OR @Period = 0 OR (SELECT PerClosedTimestamp 
           FROM Period 
           WHERE 
            PerCompanyID = @CompanyID AND 
            PerYear = @Year AND 
            PerPeriod = @Period) IS NULL 

の線に沿って何かをUNION ALL代わりにIF/THEN、しようとする誘惑されると思います。

0

おかげさまで、皆様のご意見をお寄せいただきありがとうございます。データウェアハウステーブルまたはトランザクションテーブルのいずれかからデータを返す2つの別々の関数を作成しました。私はIF THEN ELSEステートメント内の関数から選択し、それは私の問題を解決したようです。