如何查询一个错误的“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
这里是直接比较https://www.brentozar.com/pastetheplan/?id=S1hTRr59W与(SELECT @Notify)
https://www.brentozar.com/pastetheplan/?id=Hk27lI9cW
与(SELECT @Notify)查询返回0记录
根据您的版本SQL SERVER 2008 Express Edition with Advanced Services
我想这是一个错误的计划。直接比较不起作用
@Notify = 13005
但
(SELECT @Notify) = 13005
的行为,因为它应该。
我也想尝试:
- 为原始查询设置Forced Parametrization。
- 恢复您的数据库现代SQL Server上2012+
这是一个直接比较的计划https://www.brentozar.com/pastetheplan/?id=S1hTRr59W和选择https://www.brentozar.com/pastetheplan/?id=Hk27lI9cW – ventik
强制参数化并没有帮助,所以我想这个问题是在旧版本。我应该安装所有的服务包或者升级sql服务器版本。谢谢! – ventik
特别是这个bug已经修复https://connect.microsoft.com/SQLServer/feedbackdetail/view/377268/condition-in-where-clause-incorrectly-pushed-to-key-lookup-for-outer-加入 –
我同意这看起来这是fixed in CU2(FIX查询优化器的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))
- 残余谓词有215行要在以左外连接
DocOut
- 其中179个匹配表中的单个行。这个查找操作符返回一个名为
IsBaseRow1010
的系统生成列以及表中的ID列。 - 执行密钥查找的嵌套循环运算符在
IsBaseRow1010 IS NULL
上有一个传递谓词,这意味着对于外部联接无法找到匹配的行将跳过密钥查找。 - 键查找执行179次并返回0行,因为没有与谓词匹配。
- 由外连接保留的36行,其中
IsBaseRow1010 IS NULL
永远不会获得评估的谓词,并最终作为结果输出。
当您更改查询文本(select @Notify) = 13005
等OR
被表示为一个半加入对两名一排虚表的UNION ALL
与应用的过滤器,而不是在查找剩余谓词,等等该错误被避免。
非常感谢您的详细解释! – ventik
请后执行计划https://www.brentozar.com/pastetheplan/ – lad2025
尝试改变'@Notify = 13005'到'(SELECT @Notify)= 13005'和相同的第二。 – lad2025
@ lad2025增加了计划以 – ventik