我有以下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
Run Code Online (Sandbox Code Playgroud)
当我保留最后一行的注释时,我得到0个结果,但是当我取消注释它并注释它之前的行时,我得到了一些结果。
这怎么可能?
Mar*_*ith 10
Any row meeting (T.stratId = 7 AND TT.stratId = 7) must certainly meet (T.stratId = 7 OR TT.stratId = 7) so it is not logically possible that the less restrictive predicate returns less results.
The issue is a corrupt non clustered index.
And Case
TradeCore matching the date condition and stratId = 7 are emitted.TradeTransfer with the stratId and fundId conditions applied ouputs 68 rows (estimated 34 rows)Sec (using index IX_Sec_secId_sectype_Ccy_valpoint) and 68 rows are returned as the final result.Or case
TradeCore matching the date condition are emittedTradeTransfer with a residual predicate on 3 in (T.fundId, TT.fundId) AND 7 in (T.stratId, TT.stratId) brings this down to 73 (estimated 297 rows)The table cardinality of Sec is 2399 rows. In the plan where all rows are removed by the join SQL Server does a full scan on IX_Sec_idu as input to the probe side of the hash join but the full scan on that index only returns 589 rows.
The rows that appear in the other execution plan are pulled from a different index that contains these 1,810 missing rows.
You have confirmed in the comments that the following return differing results
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
Run Code Online (Sandbox Code Playgroud)
This should never be the case that rowcounts from different indexes on the same table don't match (except if an index is filtered and that does not apply here).
因为Sec在这种AND情况下,行估计只有34个连接,所以它选择了一个带有嵌套循环的计划,因此需要一个带有前导列的索引secId来执行查找。对于这种OR情况,它估计297行,而不是进行297次搜索,而是选择一个哈希联接,因此选择包含该secId列的最小可用索引。
由于所有行都存在于聚集索引中,因此您可以删除IX_Sec_idul并再次创建它以希望解决此问题(首先进行备份)。
您还应该运行dbcc checkdb以查看是否还有其他问题。