我一直在使用此方法来过滤我的查询:
Create PROCEDURE [dbo].[pGetTask]
@showCompletedTasks bit = 1
,@showInProgressTasks bit = 1
,@taskID int = null
,@projectID int = null
,@applicationID int = null
,@clientID int = null
... Snip ...
where
a.clientID = isnull(@clientID, a.clientID)
and a.applicationID = isnull(@applicationID, a.applicationID)
and p.projectID = isnull(@projectID, p.projectID)
and t.taskID = isnull(@taskID, t.taskID)
and curr.complete = case @showCompletedTasks when 0 then 0 else curr.complete end
and curr.complete = case @showInProgressTasks when 0 then 1 else curr.complete end
这实际上会使我的查询在664行结果集上减慢2秒。 SQL调优顾问没有多大帮助,所以我认为这不是正确的方法。除了大量的if语句之外,还有正确的方法吗?
答案 0 :(得分:6)
假设您已正确索引选择所在的表,并且这些字段是索引的一部分,我的猜测是它将是对isnull的调用。我会改变它们:
(@clientID is null or a.clientID = @clientId) and ...
至于case语句,位字段的索引是没有意义的,因此没有太多可做的事情。
答案 1 :(得分:2)
检查索引&统计。这看起来有点慢。另一种选择是进行动态查询,实质上是构建一个表示你的sql的字符串,并使用sp_ExecuteSql(或exec语句)执行它
您可以尝试将两种情况合并,但我怀疑它会对查询的性能产生影响。虽然看起来会更好......
虽然我不确定你的查询是否正确(如果没有更多信息,这很难说),但是在你试图提供两个状态返回的情况之间不应该存在或者条款,并且我假设我可以要求仅完成,仅完成或两者都有...在这种情况下,您需要一个或
答案 2 :(得分:1)
您最好的选择是使用此存储过程调用一系列更具体的过程。你有两个问题:
如果您创建特定的过程,例如pGetTask_Completed和pGetTask_InProgress,并在此过程中有条件地调用它们,那么您应该没有任何问题。
答案 3 :(得分:1)
你可能成为“参数嗅探”问题的受害者。 MS-SQL将把您第一次运行SP的参数作为制定查询计划的最佳样本。由于这个原因,您的查询可能会很慢。
要证明,请尝试通过将填充的参数模拟为变量来直接运行查询的内容。如果它快得多,那么你确实遇到了“参数嗅探”问题。
解决方案是欺骗MS-SQL认为您的参数仅用于分配给另一个变量。例如:
create proc ManyParams
(
@pcol1 int,
@pcol2 int,
@pcol3 int
)
as
declare
@col1 int,
@col2 int,
@col3 int
select
@col1 = @pcol1,
@col2 = @pcol2,
@col3 = @pcol3
select
col1,
col2,
col3
from
tbl
where
1 = case when @col1 is null then 1 else case when col1 = @col1 then 1 else 0 end end
and 1 = case when @col2 is null then 1 else case when col2 = @col2 then 1 else 0 end end
and 1 = case when @col3 is null then 1 else case when col3 = @col3 then 1 else 0 end end
答案 4 :(得分:0)
这是一篇关于这个主题的精彩文章:
http://www.sommarskog.se/dyn-search-2005.html
它会给你很多尝试的想法。
我倾向于混合使用这些“搜索”类型的查询。以下是我似乎一直使用的一些内容:
我尝试使某些搜索参数成为必需,因此您可以在这些参数上点击索引。
如果可能(取决于行数),使用临时表拆分查询。如果您只有几百个ClientID值,请创建一个#ClientID临时表。放入用户想要的或全部的。然后,您可以将FROM表和/或内部联接到其他表中,以使其更快。
如果您的日期是可选的,请不要使用(@startDate为null或a.date> = @startDate)。做一些像SET @ startDate = COALESCE(@ startDate,'01 / 01/1970')的事情。这将为您提供一个值并消除使用“OR”并将使用索引。
答案 5 :(得分:0)
casperOne的建议就是我要开始的。
另一种可能性是:
WHERE
(1 =
CASE
WHEN @client_id IS NULL THEN 1
WHEN a.clientID = @clientID THEN 1
ELSE 0
END) AND
...
我发现使用CASE语句的SQL Server(至少2005年)会导致查询计划短路其余的逻辑。在简单比较的情况下,这并不是一个大问题,但如果您的逻辑包含子查询或其他一些昂贵的操作,那么将其短路可能是一个很大的帮助。在你的例子中,我只会考虑casperOne的建议。
另外,如果您使用上面的CASE方法,则需要将RECOMPILE选项添加到SELECT和存储过程中。