如果Apps.mfrId爲null,那麼您將加入每個製造商。
從您的測試, 「OR ISNULL(apps.mfrId,0)= 0」 確實比這個更便宜的 「OR Apps.mfrId爲空或Apps.mfrId = 0」
這些做似乎很等價的,你已經有了一個解決方案,所以問題是爲什麼和/或如何讓非表演者工作。
說到這樣的表現,如果你說的一切都是正確的,當我們開始問爲什麼時,我們開始指向查詢優化器。如果它對於相同的參數表現不同,它將有不同的查詢計劃。您可能會看到表掃描而不是索引使用情況,或者對性能不佳的其他解釋。
我鼓勵你比較一下查詢計劃,或者讓別人來幫助引入一個關於它在做什麼不同的答案。但是,你已經可以告訴它正在做一些不同的事情。
一種可能性是,當查詢優化器修復被釋放,他們在默認情況下不開啓,除非標誌4199(所有修正或其他標誌的具體修正)被開啓。這是因爲一般修補程序對於大多數人來說可能是好的,但是也可能會破壞在現有的怪癖環境中進行了優化的應用程序。
https://dba.stackexchange.com/questions/102292/trace-flag-4199-enable-globally
是否在幫助開啓4199?
select top 2000 Apps.object_id
from
Manufacturer
INNER JOIN Apps ON (
Apps.mfrId = Manufacturer.Id
OR Apps.mfrId IS NULL
OR Apps.mfrId = 0
)
where
Apps.OBJECT_ID = 6879149
OPTION(QUERYTRACEON 4199)
另一個相關的議題是參數嗅探。有時候查詢計劃可能會被緩存,這對於一個參數是最佳的,但是對於另一個參數是可怕的。在你的情況下,一個應用程序可能會返回1個製造商,但另一個應用程序可能會返回所有制造商,這就是值得一提的原因。這通常顯示爲相同的代碼在給定不同參數時不一致地執行不良。 您可以嘗試關閉參數嗅探或強制重新編譯以幫助診斷問題是否成爲問題的一部分。
What are the main differences between OPTION(OPTIMIZE FOR UNKNOWN) and OPTION(RECOMPILE)?
我曾經見過,如果覺得查詢優化器的情況下已經放棄細讀指標,只是因爲該語句變得過於複雜。但在你的例子中這似乎不太可能;除了查詢優化器錯誤的問題得到解決之外,要利用它們,您仍然必須打開查詢標記,否則您安裝的補丁可能無法做任何事情。
有時您還可以嘗試幫助指導sql優化器。如果應該總是使用一個索引,那麼可以將其作爲查詢提示給出。
我也很好奇知道,如果以下刪除問題:如果所有的查詢優化器修復被打開
select top 2000 Apps.object_id
from
(
select Apps.object_id, Apps.mfrId
from Apps
where Apps.OBJECT_ID = 6879149
) Apps
left join Manufacturer ON (
Apps.mfrId = Manufacturer.Id
OR Apps.mfrId IS NULL
OR Apps.mfrId = 0)
,問題仍然存在,我們要問,爲什麼查詢優化器做這個。它只能使用存在的索引,並且只有在存在統計信息的情況下才能確定使用索引是否有利。同時,過時的統計數據將導致不好的選擇。定期重建/重組索引並更新統計信息可能會很好。你可能想嘗試這樣做,看看它是否有任何影響。
結論
既然你已經有了一個固定的工作,不要使用它。但是你的問題是爲什麼兩個非常相似的事情會達到非常不同的結果。假設正在使用相同的參數,並且包括兩個選項非常相似的事實,則問題指向查詢優化器是一個不好的選擇。這表明您可能需要安裝最新的修補程序(如果未安裝),並且還啓用4199以實際啓用您已通過sql server修補程序安裝的所有查詢優化程序修補程序。這包括將OPTION(QUERYTRACEON 4199)添加到sql的底部,或者在全局啓用4199或類似的。
您是否顯示每個查詢的執行計劃? –
連接條件看起來非常奇怪。這是一個左連接,內連接,?我感興趣的是爲什麼你想要一個連接條件,如果apps.mfrid爲空將被覆蓋。聽起來像你只是想完全加入。什麼是最終目標? – scsimon
@scsimon這是一個內部連接。我正在使用我沒有設計的桌子。 Apps.mfrId是Manufacturer.id的空(null)外鍵(沒有外鍵約束設置)。出於某種原因,原始設計允許NULL或0,並且NULL或0具有相同的含義(即沒有設置有效值)。 –