6

我的查询需要在某些列上是动态的,这意味着我得到一个参数并根据它的值决定在 Where 子句中获取哪一列。我已经使用“CASE”表达式实现了这个请求:

(CASE @isArrivalTime WHEN 1 THEN ArrivalTime ELSE PickedupTime END) 
>= DATEADD(mi, -@TZOffsetInMins, @sTime) 
 AND (CASE @isArrivalTime WHEN 1 THEN ArrivalTime ELSE PickedupTime END) 
 < DATEADD(mi, -@TZOffsetInMins, @fTime)

如果@isArrivalTime = 1然后选择ArrivalTime列,则选择PickedupTime列。我有一个聚集索引ArrivalTime和非聚集索引PickedupTime

我注意到,当我使用此查询(使用@isArrivalTime = 1)时,与仅使用ArrivalTime.

也许查询优化器不能以这种方式正确使用\选择索引?

我比较了执行计划并注意到,当我使用CASE32% 的时间被浪费在索引扫描上时,但是当我没有使用 CASE (just usedArrivalTime`) 时,只有 3% 的时间被浪费在了索引扫描上。

有谁知道这是什么原因?

4

2 回答 2

3

两者之间的差异很可能是由于它必须扫描的行数不同。由于您的查询很可能是更多表之间连接的最终结果。请记住,扫描是.. 顾名思义,扫描所有行。您可以在计划中检查估计的行数以做出想法。

如果您在动态字段上使用过滤器(例如用例),则引擎无法使用该字段上的索引。在这种情况下,您最好使用动态 sql 来生成您需要的正确 sql 并使用 exec_sql。或者使用 if 语句直接查询正确的内容。

您可能会发现这对于使用动态 sql 很有用,它将解释原因和方式。

http://www.sommarskog.se/dynamic_sql.html

于 2012-09-16T09:25:03.343 回答
0

尝试设置日期时间边界:

declare @resSTime datetime
        ,@resFTime datetime

set @resSTime = DATEADD(mi, -@TZOffsetInMins, @sTime)
set @resFTime = DATEADD(mi, -@TZOffsetInMins, @fTime)

并尝试将大小写更改为“或”

( ArrivalTime >= @resSTime 
    and ArrivalTime < @resFTime 
    and @isArrivalTime = 1 )
or ( PickedupTime >= @resSTime 
    and PickedupTime < @resFTime 
    and @isArrivalTime <> 1 )
于 2012-09-18T08:04:31.303 回答