请考虑以下代码:
declare @var bit = 0
select * from tableA as A
where
1=
(case when @var = 0 then 1
when exists(select null from tableB as B where A.id=B.id)
then 1
else 0
end)
由于变量@var设置为0,因此评估搜索案例运算符的结果为1.在案例文档中,写入它直到第一个WHEN为TRUE时才进行求值。但是当我查看执行计划时,我也看到了tableB也被扫描了。
有人知道为什么会这样吗?当另一个逻辑条件被评估为TRUE时,可能有一些方法可以避免第二个表扫描?
答案 0 :(得分:3)
因为编译和缓存的计划需要适用于@var
您需要使用类似
的内容if (@var = 0)
select * from tableA
else
select * from tableA as A
where exists(select * from tableB as B where A.id=B.id)
即使OPTION RECOMPILE
看起来也不会有帮助。它仍然没有为您提供文字0=0
declare @var bit = 0
select * from
master.dbo.spt_values as A
where
1=
(case when 0 = @var then 1
when exists(select null from master.dbo.spt_values as B where A.number=B.number)
then 1
else 0
end)
option(recompile)
Plan http://img189.imageshack.us/img189/3977/executionplan.jpg
select * from
master.dbo.spt_values as A
where
1=
(case when 0 = 0 then 1
when exists(select null from master.dbo.spt_values as B where A.number=B.number)
then 1
else 0
end)
Plan http://img193.imageshack.us/img193/3977/executionplan.jpg
RE:评论中的问题。在启用“包括实际执行计划”选项的情况下尝试以下操作。
declare @var bit = datepart(second,GETDATE())%2
print @var
if (@var = 0)
select * from
master.dbo.spt_values --8BA71BA5-3025-4967-A0C8-38B9FBEF8BAD
else
select * from
master.dbo.spt_values as A --8BA71BA5-3025-4967-A0C8-38B9FBEF8BAD
where exists(select null from master.dbo.spt_values as B where A.number=B.number)
然后尝试
SELECT usecounts, cacheobjtype, objtype, text, query_plan
FROM sys.dm_exec_cached_plans
CROSS APPLY sys.dm_exec_sql_text(plan_handle)
CROSS APPLY sys.dm_exec_query_plan(plan_handle)
where text like '%8BA71BA5-3025-4967-A0C8-38B9FBEF8BAD%'
编译计划看起来像
Plan http://img178.imageshack.us/img178/3977/executionplan.jpg
实际执行计划将仅显示实际执行的一条路径。
答案 1 :(得分:1)
如果tableB的行数很少,则表扫描是最快的方法。
动态搜索条件的最佳来源:
Dynamic Search Conditions in T-SQL by Erland Sommarskog
如果可以使用索引,对于如何执行此操作会有很多微妙的含义。如果您使用的是SQL Server 2008的正确版本,则只需将OPTION (RECOMPILE)
添加到查询中,并将运行时的局部变量值用于优化。
考虑到这一点,OPTION (RECOMPILE)
将采用此代码(其中没有索引可用于此OR
的混乱):
WHERE
(@search1 IS NULL or Column1=@Search1)
AND (@search2 IS NULL or Column2=@Search2)
AND (@search3 IS NULL or Column3=@Search3)
并在运行时优化它(假设只有@ Search2传入了一个值):
WHERE
Column2=@Search2
并且可以使用索引(如果在Column2上定义了一个索引)