この同様の質問への答えをこちらでご覧ください:https :
//stackoverflow.com/questions/11329823/add-where-clauses-to-sql-dynamically-programmatically
一連のオプションのパラメーターを取り込んで、次のようなフィルターを実装するSPROCが見つかりました。
CREATE PROC MyProc (@optionalParam1 NVARCHAR(50)=NULL, @optionalParam2 INT=NULL)
AS
...
SELECT field1, field2, ... FROM [Table]
WHERE
(@optionalParam1 IS NULL OR MyColumn1 = @optionalParam1)
AND (@optionalParam2 IS NULL OR MyColumn2 = @optionalParam2)
で実行される最初の実行プランをキャッシュし@optionalParam1 = 'Hello World', @optionalParam2 = NULL
ますが(たとえば@optionalParam1 = NULL, @optionalParam2 = 42
)、オプションのパラメーターの別のセット(たとえば)を渡すと、ひどく実行します。(そして明らかに、キャッシュされたプランのパフォーマンスが欲しいので、そうWITH RECOMPILE
です)
ここでの例外は、オプションのパラメーターに加えて、選択性が高く適切にインデックスが付けられたクエリに少なくとも1つの必須フィルターがある場合、上記のPROCは正常に実行されることです。
ただし、すべてのフィルターがオプションである場合、かなりひどい真実は、パラメーター化された動的SQLのパフォーマンスが実際に向上することです(オプションのパラメーターの順列ごとにN!の異なる静的PROCSを記述しない限り)。
以下のような動的SQLは、クエリパラメーターの順列ごとに異なるプランを作成してキャッシュしますが、少なくとも各プランは特定のクエリに合わせて「調整」されます(PROCかアドホックSQLかは関係ありません。パラメータ化されたクエリである限り、キャッシュされます)
したがって、私の好みは:
DECLARE @SQL NVARCHAR(MAX)
-- Mandatory / Static part of the Query here
SET @SQL = N'SELECT * FROM [table] WHERE 1 = 1'
IF @OptionalParam1 IS NOT NULL
BEGIN
SET @SQL = @SQL + N' AND MyColumn1 = @optionalParam1'
END
IF @OptionalParam2 IS NOT NULL
BEGIN
SET @SQL = @SQL + N' AND MyColumn2 = @optionalParam2'
END
EXEC sp_executesql @SQL,
N'@optionalParam1 NVARCHAR(50),
@optionalParam2 INT'
,@optionalParam1 = @optionalParam1
,@optionalParam2 = @optionalParam2
など。冗長パラメータをsp_executesqlに渡しても構いません-それらは無視されます。Linq2SQLやEFのようなORMがパラメータ化された動的SQLを同様の方法で使用していることは注目に値します。