我用可选参数编写了一个存储过程。
CREATE PROCEDURE dbo.GetActiveEmployee
@startTime DATETIME=NULL,
@endTime DATETIME=NULL
AS
SET NOCOUNT ON
SELECT columns
FROM table
WHERE (@startTime is NULL or table.StartTime >= @startTime) AND
(@endTIme is NULL or table.EndTime <= @endTime)
我想知道是否会使用StartTime和EndTime上的索引?
答案 0 :(得分:4)
是的,他们将被使用(很可能,检查执行计划 - 但我知道你的参数的可选性不应该有任何区别)
如果您的查询出现性能问题,则可能是参数嗅探的结果。尝试以下存储过程的变体,看看它是否有所不同:
CREATE PROCEDURE dbo.GetActiveEmployee
@startTime DATETIME=NULL,
@endTime DATETIME=NULL
AS
SET NOCOUNT ON
DECLARE @startTimeCopy DATETIME
DECLARE @endTimeCopy DATETIME
set @startTimeCopy = @startTime
set @endTimeCopy = @endTime
SELECT columns
FROM table
WHERE (@startTimeCopy is NULL or table.StartTime >= @startTimeCopy) AND
(@endTimeCopy is NULL or table.EndTime <= @endTimeCopy)
这会禁用参数嗅探(SQL服务器使用传递给SP的实际值来优化它) - 过去我已经解决了一些奇怪的性能问题 - 我仍然无法令人满意地解释原因。
您可能想要尝试的另一件事是根据参数的NULL值将查询拆分为多个不同的语句:
IF @startTime is NULL
BEGIN
IF @endTime IS NULL
SELECT columns FROM table
ELSE
SELECT columns FROM table WHERE table.EndTime <= @endTime
END
ELSE
IF @endTime IS NULL
SELECT columns FROM table WHERE table.StartTime >= @startTime
ELSE
SELECT columns FROM table WHERE table.StartTime >= @startTime AND table.EndTime <= @endTime
BEGIN
这很麻烦,但是如果遇到问题可能值得一试 - 它之所以有帮助,是因为SQL服务器每个sql语句只能有一个执行计划,但是你的语句可能会返回截然不同的结果集。 / p>
例如,如果传入NULL和NULL,则将返回整个表和最佳执行计划,但是如果传入一小段日期,则行查找更有可能是最佳执行计划。
将此查询作为单个语句,SQL服务器必须在这两个选项之间进行选择,因此在某些情况下查询计划可能不是最佳的。通过将查询拆分为多个语句,SQL Server可以在每种情况下都有不同的执行计划。
(如果您愿意,也可以使用exec
函数/动态SQL来实现相同的目标)
答案 1 :(得分:2)
有一篇很棒的文章与SQL中的动态搜索条件有关。我个人在文章中使用的方法是X = @X或@X IS NULL样式,最后添加了OPTION(RECOMPILE)。如果您阅读该文章,它将解释原因
答案 2 :(得分:1)
是的,根据查询提供的StartTime
和EndTime
列上的索引可以使用。
但是,[variable] IS NULL OR...
使查询无法进行查询。如果您不想使用IF语句(因为CASE是一个表达式,并且不能用于控制流决策逻辑),动态SQL是性能SQL的下一个替代方法。
IF @startTime IS NOT NULL AND @endTime IS NOT NULL
BEGIN
SELECT columns
FROM TABLE
WHERE starttime >= @startTime
AND endtime <= @endTime
END
ELSE IF @startTime IS NOT NULL
BEGIN
SELECT columns
FROM TABLE
WHERE endtime <= @endTime
END
ELSE IF @endTIme IS NOT NULL
BEGIN
SELECT columns
FROM TABLE
WHERE starttime >= @startTime
END
ELSE
BEGIN
SELECT columns
FROM TABLE
END
答案 3 :(得分:1)
基于给定参数动态更改搜索是一个复杂的主题,并且以一种方式对其进行操作,即使只有非常小的差异,也会产生巨大的性能影响。关键是使用索引,忽略紧凑代码,忽略担心重复代码,必须做出好的查询执行计划(使用索引)。
阅读本文并考虑所有方法。您最好的方法取决于您的参数,数据,架构和实际使用情况:
Dynamic Search Conditions in T-SQL by by Erland Sommarskog
The Curse and Blessings of Dynamic SQL by Erland Sommarskog
上述文章中适用于此查询的部分是Umachandar's Bag of Tricks,但它基本上将参数默认为某个值以消除需要使用OR。这将提供最佳的索引使用和整体性能:
CREATE PROCEDURE dbo.GetActiveEmployee
@startTime DATETIME=NULL,
@endTime DATETIME=NULL
AS
SET NOCOUNT ON
DECLARE @startTimeCopy DATETIME
DECLARE @endTimeCopy DATETIME
set @startTimeCopy = COALESCE(@startTime,'01/01/1753')
set @endTimeCopy = COALESCE(@endTime,'12/31/9999')
SELECT columns
FROM table
WHERE table.StartTime >= @startTimeCopy AND table.EndTime <= @endTimeCopy)
答案 4 :(得分:0)
可能不是。看一下Tony Rogerson SQL Server MVP的博客文章:
http://sqlblogcasts.com/blogs/tonyrogerson/archive/2006/05/17/444.aspx
您至少应该知道需要使用可靠的数据进行测试并检查执行计划。
答案 5 :(得分:-1)
我认为您无法保证将使用该索引。它将在很大程度上取决于表的大小,显示的列,索引的结构和其他因素。
您最好的选择是使用SQL Server Management Studio(SSMS)并运行查询,并包含“实际执行计划”。然后你可以研究它,看看究竟使用了哪个指数。
你会经常对你所发现的东西感到惊讶。
如果查询中有OR
或IN
,则情况尤其如此。