2017-09-16 147 views
2

這是一個查詢。 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

回答

1

與(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-加入 –

3

我同意這看起來這是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