如何用false“where”条件查询返回结果?

时间:2017-09-16 06:52:26

标签: sql sql-server tsql

这是一个查询。 Where子句包含两部分,它们都是假的(因为@Notify不等于13005或13105)。

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

  

SQL SERVER版本 - Microsoft SQL Server 2008(RTM) - 10.0.1600.22   (英特尔X86)         2008年7月9日14:43:34         版权所有(c)1988-2008 Microsoft Corporation         在Windows NT 6.1(Build 7601:Service Pack 1)上使用高级服务的Express Edition(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

的计划

2 个答案:

答案 0 :(得分:3)

我同意这看起来像查询优化器错误(specifically this onefixed in CU2 FIX:如果直通谓词与其查询中的过滤器一起使用,则查询可能会返回错误的结果计划)。对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. DocOut
  2. 左边的外部联接中有215行
  3. 其中179个匹配表中的一行。此查找运算符返回一个名为IsBaseRow1010的系统生成列以及表中的ID列。
  4. 执行密钥查找的嵌套循环运算符在IsBaseRow1010 IS NULL上有一个遍历谓词,这意味着对于外部联接未能找到匹配项的行,将跳过密钥查找。
  5. 密钥查找执行179次并返回0行,因为没有与谓词匹配。
  6. 由外部联接保留的36行,其中IsBaseRow1010 IS NULL永远不会获得评估的谓词,并最终作为结果输出。
  7. 当您将查询文本更改为(select @Notify) = 13005等时,OR将被表示为半连接,对应于应用了过滤器的两个一行虚拟表中的UNION ALL,而不是查找的残差谓词,因此可以避免错误。

    enter image description here

答案 1 :(得分:1)

  

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

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

@Notify = 13005

但是

(SELECT @Notify) = 13005

表现得如此。

我也会尝试: