您可能想在这里查看类似问题的答案: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
已淘汰)
这里的例外是,如果在查询上还至少有一个MANDATORY过滤器,除了可选参数之外,该过滤器具有高度选择性和正确索引,那么上面的PROC会很好地执行。
但是,如果所有过滤器都是可选的,那么可怕的事实是,参数化的动态sql实际上会更好(除非您为可选参数的每个排列编写N!个不同的静态PROCS)。
如下所示的动态SQL将为Query参数的每个排列创建并缓存一个不同的计划,但是至少每个计划都将“定制”到特定的查询(无论是PROC还是Adhoc 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。