2016-11-28 4 views
0

私はEmployeeというテーブルを持っています。 フィールドは、私は、すべての従業員の詳細をフェッチする手順を記述する必要が動的クラス 'CASE'を使用するとパフォーマンスに影響します

1.EmployeeId、 2.Name、 3.Salary、 4.Address

です。このプロシージャのwhere句は動的です。私は詳細を取得する動的クエリを書くことができます。しかし、私は最近、以下のフォーマットのクエリを探求します。

SELECT * FROM Employee 
WHERE 1=1 
AND EmployeeId = CASE WHEN @EmployeeId IS NULL OR LEN(@EmployeeId) =0 THEN EmployeeId ELSE @EmployeeId END 
AND Name = CASE WHEN @Name IS NULL OR LEN(@Name) =0 THEN Name ELSE @Name END 
... 
... 
ORDER BY Name ASC 

@EmployeeId、@nameは、アプリケーション

からのいずれかが、これは、動的クエリに対する任意のパフォーマンスへの影響を行います教えてもらえますしていますか?どちらが優れたパフォーマンスですか?

where句の条件は動的です。これは2条件で厳密ではありません。いずれのタイプミス・エラーのために申し訳ありませんが、いくつかの倍の1または3または4または0

事前に

感謝。

+1

明らかに、MySQLとSQLサーバーの両方を使用していないので追加したデータベースタグを削除しました。実際に使用しているRDMSのタグだけを追加してください。 –

+0

「EmployeeID」と「Name」はどこから来ますか?彼らはあなたのテーブルの 'Employee'の列ですか? –

+0

16個の可能なバリエーションの検索条件で 'if' /' then'/'else'ツリーを作成し、適切なクエリを実行することができます。または、検索基準に基づいてストアドプロシージャ名をアセンブルし、SPを実行します。どちらの方法でも、事前にコンパイルされた「最適な」クエリを使用できます。脇に:本当にすべての列を調べ、 'NULL'値を含む行を拒否しようとしていますか?もしそうでなければ、 '@NameがNULLか@Name = ''か(Name = @Name)、そして、1 else 0 end = 1'のようなものが必要になります。 – HABO

答えて

0

のは、これはあなたが作業しているデータだったとしましょう:

-- sample data 
USE tempdb; 
GO 
CREATE TABLE dbo.employee (EmployeeId int, Name varchar(100)); 
INSERT dbo.employee 
SELECT TOP (100) 
    ABS(checksum(newid())%10)+1, 
    CASE abs(checksum(newid())%3)+1 WHEN 1 THEN 'Peter' WHEN 2 THEN 'Paul' ELSE 'Mary' END 
    + ' ' + 
    CASE abs(checksum(newid())%3)+1 WHEN 1 THEN 'Smith' WHEN 2 THEN 'Jones' ELSE 'White' END 
FROM sys.all_columns; 

-- A good covering index 
CREATE NONCLUSTERED INDEX nc_employee ON dbo.employee (EmployeeId, Name); 

このクエリとまったく同じ結果と実行計画を取得することができます最初のノート:

SELECT * 
FROM dbo.employee 
WHERE (EmployeeId = @EmployeeId OR NULLIF(LEN(@EmployeeId),0) IS NULL) 
AND (Name  = @Name  OR NULLIF(LEN(@Name),0)  IS NULL) 

があると仮定使用可能なインデックスが存在する - クエリ(または上記のクエリ)は、インデックスシークまたはインデックススキャンとSELECT演算子で構成される基本実行プランを作成します。そのままでクエリを実行するとスキャンします。いずれかのクエリの最後にOPTION(RECOMPILE)を含めるとシークします。インデックスのシークはスキャンよりはるかに優れています。

前述のOPTION(RECOMPILE)ヒントを使用してインデックスシークを取得する代わりに、以下に示すように動的SQLを使用することもできます。あなたはスキャンを取得します -

DECLARE @EmployeeId int = 5, 
     @Name varchar(100) = 'Peter White'; 

DECLARE @sql nvarchar(2000) = N'SELECT * FROM dbo.employee'; 
DECLARE @ParmDefinition nvarchar(500); 
SET @ParmDefinition = N'@EmployeeId int, @Name varchar(100)'; 

SET @sql += 
CASE 
    WHEN (NULLIF(LEN(@EmployeeId),0) IS NOT NULL AND NULLIF(LEN(@Name),0) IS NOT NULL) 
    THEN ' WHERE EmployeeId = @EmployeeId AND Name = @Name;' 
    WHEN (NULLIF(LEN(@EmployeeId),0) IS NULL AND NULLIF(LEN(@Name),0) IS NOT NULL) 
    THEN ' WHERE Name = @Name;' 
    WHEN (NULLIF(LEN(@EmployeeId),0) IS NOT NULL AND NULLIF(LEN(@Name),0) IS NULL) 
    THEN ' WHERE EmployeeId = @EmployeeId;' 
    ELSE '' 
END; 

EXECUTE sp_executesql @sql, @ParmDefinition, @EmployeeId = @EmployeeId, @Name = @Name; 

は最後に、それは@EmployeeIDがNULLまたは空白ですが、@Nameが値を持っている場合のために、ということは注目に値します。これらのケースでシークしたい場合は、次のような別のインデックスが必要になります。

CREATE NONCLUSTERED INDEX nc_employee2 ON dbo.employee (Name, EmployeeId); 
+0

OPの元のクエリは、 'EmployeeId'または' Name'が 'NULL'のすべての行をフィルタリングします。あなたはその機能を維持していませんが、それは意図的ではありませんでした。 – HABO

+0

こんにちは、ありがとうございます。しかし、私の問題は、where句では動的です。 where句にアプリケーションロジックに基づいて1または2または3または4の条件が含まれる場合。このシナリオではどのフォーマットが完璧でしょうか?いくつかの時間も条件が来ることはありません。 –

関連する問題