sql-server - SQL Server 2016 奇怪的行为 - OR 条件给出 0 行但 AND 条件给出了一些行
问题描述
我有以下 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)
,因此限制较少的谓词返回较少的结果在逻辑上是不可能的。
问题是损坏的非聚集索引。
和案例
TradeCore
匹配日期条件和stratId = 7的154行被发出。- 加入
TradeTransfer
并应用stratId
条件fundId
输出 68 行(估计 34 行) - 这些都成功加入
Sec
(使用索引 IX_Sec_secId_sectype_Ccy_valpoint)中的一行,并返回 68 行作为最终结果。
或案例
- 发出1173 行
TradeCore
匹配日期条件 - 加入
TradeTransfer
残差谓词 on3 in (T.fundId, TT.fundId) AND 7 in (T.stratId, TT.stratId)
将其减少到 73(估计为 297 行) - 然后通过 Sec 上的连接消除所有行 - 尽管我们从上面知道其中至少有 68 个有匹配项。
的表基数Sec
是2399
行。在连接删除所有行的计划中,SQL Server 对IX_Sec_idu
作为散列连接的探测端的输入进行完全扫描,但对该索引的完全扫描仅返回 589 行。
另一个执行计划中出现的行是从包含这 1,810 个缺失行的不同索引中提取的。
您已在评论中确认以下返回不同的结果
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
以查看是否存在任何其他问题。
推荐阅读
- prolog - 如何读取原子列表?
- android - 导航抽屉活动中菜单项的 OnClickListener
- reactjs - 乐观的 ui 更新 - 反应
- javascript - Firebase 网络推送通知发送成功但客户端未收到
- php - 如何将 data-oembed-url 数据替换为其他 html 标记
- c - 输出显示 C 中不必要的数字
- python - 为什么 VSCode 中的“import”带有红色下划线?
- sql - 在 SQL 中撤销权限时的默认行为是什么?
- django - 如何将评论与 Django 模型中的父评论相关联
- twitter-bootstrap - Boostrap sass 函数,(scss 中的混合函数)?