SWa*_*SWa 5 sql-server sql-server-2008-r2
我有一个旧的数据库使用char(1)
与'T'
和'F'
布尔值。该字段中的唯一值是T
and 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)
这使数据库使用与第一个查询相同的索引并立即执行,但我更愿意了解实际发生的情况。我在阅读执行计划方面非常绿色,但是对于可能发生的事情的一些指示将不胜感激。
从阅读周围,似乎中符合条件的会影响性能记录的预期数量,所涉及的表有更多的F
比T
:
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 ),我想我不知道,这是否真的适用于您的硬编码查询。