我有以下SQL查询:
SELECT T.tnum,
T.secId,
FROM TradeCore T
INNER JOIN Sec S
ON S.secId = T.secId
INNER JOIN TradeTransfer TT
ON t.tnum = TT.tnum
WHERE ( T.td >= '2019-01-01' )
AND ( T.td <= '2019-02-25' )
AND ( T.fundId = 3 OR TT.fundId = 3 )
AND ( T.stratId = 7 OR TT.stratId = 7 ) --Line 1
-- AND ( T.stratId = 7 AND TT.stratId = 7 ) --Line 2
当我保留最后一行的注释时,我得到0个结果,但是当我取消注释并在它前面的行中注释时,我得到了一些结果。
这怎么可能?
答案 0 :(得分:10)
任何行式会议(T.stratId = 7 AND TT.stratId = 7)
当然必须满足(T.stratId = 7 OR TT.stratId = 7)
,因此从逻辑上讲,限制性较小的谓词返回的结果较少。
问题是损坏的非聚集索引。
和案例
TradeCore
中发出TradeTransfer
和stratId
条件下加入fundId
,输出68行(估计34行)Sec
中的一行(使用索引IX_Sec_secId_sectype_Ccy_valpoint),并返回68行作为最终结果。或案例
TradeCore
中发出与日期条件匹配的TradeTransfer
并在3 in (T.fundId, TT.fundId) AND 7 in (T.stratId, TT.stratId)
上加入剩余谓词,将其减少到73(估计为297行) Sec
的表基数为2399
行。在通过联接删除所有行的计划中,SQL Server对IX_Sec_idu
进行完全扫描,作为对哈希联接的探测端的输入,但是对该索引的完全扫描仅返回589行。
另一个执行计划中出现的行是从另一个索引中提取的,该索引包含这1810个丢失的行。
您已在评论中确认以下结果返回不同的结果
select count(*) from Sec with(index = IX_Sec_idul); --589
select count(*) from Sec with(index = IX_Sec_secId_sectype_Ccy_valpoint); --2399
select count(*) from Sec with(index = PK_Sec) --2399
在任何情况下都不应该是同一张表上来自不同索引的行数不匹配的情况(除非索引被过滤并且不适用于此处)。
由于在Sec
情况下进入AND
的联接的行估计只有34个,因此选择了带有嵌套循环的计划,因此需要索引以前导列secId
进行索引执行搜寻。对于OR
情况,它估计297行,而不是进行297次搜索,而是选择一个哈希联接,因此选择包含secId
列的最小索引。
当所有行都存在于聚集索引中时,您可以删除IX_Sec_idul
并再次创建它以希望解决此问题(首先进行备份)。
您还应该运行dbcc checkdb
来查看是否还有其他问题。