如何查询一个错误的“where”条件返回结果?

问题描述:

这是一个查询。 Where子句包含两个部分,它们都是假的(因为@Notify不等于13005或13105)。如何查询一个错误的“where”条件返回结果?

但是这个查询返回36行。如果block包含false,它如何返回任何东西? CHECKDB显示没有错误,重启也没有帮助。如果我添加1 = 0条件而不是@Notify = 13005,则查询返回0行。

SQL Server版本 - 微软的SQL Server 2008(RTM) - 10.0.1600.22 (英特尔X86) 2008年7月9日14时43分34秒 版权所有(C)1988-2008微软公司 Express Edition与高级在Windows NT 6.1服务(建设7601:Service Pack 1的)(WOW64)

declare @Notify smallint 
set @Notify = 20 

select distinct DMD_ID 
    ,cast(DMD_Document as varchar) + '-' + cast(Cl_Place as varchar) as DMD_Document 
    ,DMD_Client 
from DocMoveDemand 
inner join Client on DMD_Client = Cl_ID 
inner join DocMoveDemandList on DMDL_SDoc = DMD_ID 
left outer join DocOut on DO_DocMoveDemand = DMD_ID 
where (
     @Notify = 13005 
     and DMDL_DocMoveDenyReason in (2,3,4) 
     and (
      DO_IsMove = 'Y' 
      or DMD_IsReturn = 1 
      ) 
     and DateDiff(DD, isnull(DMD_DateReturn, DO_DateMove), GETDATE()) < 14 
     and DMD_NotifyInv1 = 0 
     ) 
    or (
     @Notify = 13105 
     and DMDL_DocMoveDenyReason in (2,3,4) 
     and (
      DO_IsMove = 'Y' 
      or DMD_IsReturn = 1 
      ) 
     and DateDiff(DD, isnull(DMD_DateReturn, DO_DateMove), GETDATE()) >= 14 
     and DMD_NotifyInv2 = 0 
     ) 
order by DMD_ID 

执行计划 enter image description here

这里是直接比较https://www.brentozar.com/pastetheplan/?id=S1hTRr59W(SELECT @Notify)https://www.brentozar.com/pastetheplan/?id=Hk27lI9cW

+0

请后执行计划https://www.brentozar.com/pastetheplan/ – lad2025

+0

尝试改变'@Notify = 13005'到'(SELECT @Notify)= 13005'和相同的第二。 – lad2025

+0

@ lad2025增加了计划以 – ventik

与(SELECT @Notify)查询返回0记录

根据您的版本SQL SERVER 2008 Express Edition with Advanced Services我想这是一个错误的计划。直接比较不起作用

@Notify = 13005 

(SELECT @Notify) = 13005 

的行为,因为它应该。


我也想尝试:

+0

这是一个直接比较的计划https://www.brentozar.com/pastetheplan/?id=S1hTRr59W和选择https://www.brentozar.com/pastetheplan/?id=Hk27lI9cW – ventik

+1

强制参数化并没有帮助,所以我想这个问题是在旧版本。我应该安装所有的服务包或者升级sql服务器版本。谢谢! – ventik

+2

特别是这个bug已经修复https://connect.microsoft.com/SQLServer/feedbackdetail/view/377268/condition-in-where-clause-incorrectly-pushed-to-key-lookup-for-outer-加入 –

我同意这看起来这是fixed in CU2FIX查询优化器的bug(specifically this one):如果直通谓词与使用的查询可能返回不正确的结果其查询计划中的过滤器)。对WHERE谓词的这一位的评估被错误地推入到针对DocOut的密钥查找中,而不针对与DocOut中的任何内容不匹配的行进行评估,并且由外部连接保留。

下面的查找操作符(编号4)具有的

Seek Keys[1]: Prefix: [SMNikopol].[dbo].[DocOut].DO_ID 
       = Scalar Operator([SMNikopol].[dbo].[DocOut].[DO_ID]) 

寻道谓词和

([SMNikopol].[dbo].[DocOut].[DO_IsMove] = 'Y' 
    OR [SMNikopol].[dbo].[DocMoveDemand].[DMD_IsReturn] = (1)) 
AND ([@Notify] = (13005) 
     AND datediff(day, CONVERT_IMPLICIT(datetime, isnull([SMNikopol].[dbo].[DocMoveDemand].[DMD_DateReturn], [SMNikopol].[dbo].[DocOut].[DO_DateMove]), 0), getdate()) < (14) 
     AND [SMNikopol].[dbo].[DocMoveDemand].[DMD_NotifyInv1] = (0) 
     OR [@Notify] = (13105) 
      AND datediff(day, CONVERT_IMPLICIT(datetime, isnull([SMNikopol].[dbo].[DocMoveDemand].[DMD_DateReturn], [SMNikopol].[dbo].[DocOut].[DO_DateMove]), 0), getdate()) >= (14) 
      AND [SMNikopol].[dbo].[DocMoveDemand].[DMD_NotifyInv2] = (0)) 

enter image description here

  1. 残余谓词有215行要在以左外连接DocOut
  2. 其中179个匹配表中的单个行。这个查找操作符返回一个名为IsBaseRow1010的系统生成列以及表中的ID列。
  3. 执行密钥查找的嵌套循环运算符在IsBaseRow1010 IS NULL上有一个传递谓词,这意味着对于外部联接无法找到匹配的行将跳过密钥查找。
  4. 键查找执行179次并返回0行,因为没有与谓词匹配。
  5. 由外连接保留的36行,其中IsBaseRow1010 IS NULL永远不会获得评估的谓词,并最终作为结果输出。

当您更改查询文本(select @Notify) = 13005OR被表示为一个半加入对两名一排虚表的UNION ALL与应用的过滤器,而不是在查找剩余谓词,等等该错误被避免。

enter image description here

+0

非常感谢您的详细解释! – ventik