我有以下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个结果,但是当我取消注释并在它前面的行中注释时,我得到了一些结果。
这怎么可能?
最佳答案
任何符合(T.stratId = 7 AND TT.stratId = 7)
的行都必定必须符合(T.stratId = 7 OR TT.stratId = 7)
,因此从逻辑上讲,限制性较小的谓词返回的结果较少是不可能的。
问题是损坏的非聚集索引。
和Case
TradeCore
中与日期条件匹配且stratId = 7的154行。 TradeTransfer
和stratId
条件加入fundId
,输出68行(估计34行)Sec
中的行(使用索引IX_Sec_secId_sectype_Ccy_valpoint),并返回68行作为最终结果。 或大小写
TradeCore
中的1173行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
来查看是否还有其他问题。