搜索“T”而不是“F”时,相同的查询速度较慢

SWa*_*SWa 5 sql-server sql-server-2008-r2

我有一个旧的数据库使用char(1)'T''F'布尔值。该字段中的唯一值是Tand F,在以下查询中,第一个是瞬时的,第二个需要 30 秒。

select top 50 * from vw_Movement 
where MOVTypeId = 20 and MOVRequiresResolution = 'T' and MOVIsResolved = 'F' 

select top 50 * from vw_Movement 
where MOVTypeId = 20 and MOVRequiresResolution = 'T' and MOVIsResolved = 'T' 
Run Code Online (Sandbox Code Playgroud)

执行计划非常相似,但较慢的使用不同的索引。

修正通过改变SQL的问题:

select top 50 * from vw_Movement 
where MOVTypeId = 20 and MOVRequiresResolution = 'T' and MOVIsResolved <> 'F'  
Run Code Online (Sandbox Code Playgroud)

这使数据库使用与第一个查询相同的索引并立即执行,但我更愿意了解实际发生的情况。我在阅读执行计划方面非常绿色,但是对于可能发生的事情的一些指示将不胜感激。

从阅读周围,似乎中符合条件的会影响性能记录的预期数量,所涉及的表有更多的FT

movisresolved 
------------- -----------
T             70054
F             2734444
Run Code Online (Sandbox Code Playgroud)

这里发生了什么事?

编辑:

T 的快速索引:

CREATE NONCLUSTERED INDEX [ix_comms_composite3] ON [dbo].[tb_MOVMovement]
(
    [MOVTypeId] ASC,
    [MOVIsResolved] ASC,
    [MOVRequiresResolution] ASC,
    [MOVSupplierId] ASC,
    [MOVArrangementId] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, 
       SORT_IN_TEMPDB = OFF, DROP_EXISTING = OFF, 
       ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON
      ) ON [PRIMARY]
Run Code Online (Sandbox Code Playgroud)

经过评论的一些提示后,这只发生在针对视图运行时,而不是直接在表上运行,即:

select top 50 * from tb_MOVMovement 
where MOVTypeId = 20 and MOVRequiresResolution = 'T' and MOVIsResolved = 'F'

select top 50 * from tb_MOVMovement 
where MOVTypeId = 20 and MOVRequiresResolution = 'T' and MOVIsResolved = 'T' 
Run Code Online (Sandbox Code Playgroud)

两者都一样快,请在此处查看定义:http : //pastebin.com/raw.php?i=FER0bqwh

表脚本:http : //pastebin.com/nSpSah7b 差指数:http : //pastebin.com/V7qEpqsY 执行计划:https : //drive.google.com/file/d/0B5O3tLIEkg56bWhXcU5KcldPa2s/edit? pli =1

小智 1

正如您的请求下面的响应中已经指出的,这很肯定是由于 F 和 T 的不平衡性质导致 SQL Server 更喜欢扫描而不是查找。尽管这是相当大的简化,因为您正在查询包含大量表和 WHERE 以及 JOIN 条件的视图。

如果您查询“[...] and MOVIsResolved = 'F'”,SQL 优化器很可能更喜欢 SCAN 而不是 SEEK,因为给定的结果很大。对于“[...] ='T'”,它更喜欢 SEEK,因为结果集足够小。最后,使用“[...] <>'F'”,优化器别无选择,只能扫描并检查每个条目,该列是否不包含“F”。最后对你来说很清楚“<> F”等于“= T”,因为你知道只能有这2个。SQL Server不知道这一点。因此,“<> 'F'”和“= 'F'”的执行计划是相同的。

作为替代方案,您可能想研究 OPTION( OPTIMIZE FOR UNKNOWN ),我想我不知道,这是否真的适用于您的硬编码查询。