SqlServer 的提示符(Option/With等提示符)不是何時均可以用的

咱們在作SqlServer的查詢調優的時候,常常會在語句末尾用到option(loop/merge/hash join)或在join語句前直接聲明loop/merge/hash,來強制SqlServer使用某一特定類型的join方式。可是有些時候通過查詢優化器優化後的執行計劃可能會和你聲明的join方式產生衝突,致使執行計劃生成失敗,咱們來看一下下面這個典型案例。oop

 

declare @id1 int=1,@id2 int=1

select * 
from [dbo].[T_People] a 
 inner join [dbo].[T_People_II] b on a.id=b.id
where
a.id=@id1 and b.id=@id2
option(hash join)

咱們在上面的查詢語句中使用了option提示符強制讓SqlServer使用Hash Join來作join查詢,在執行該語句時咱們會獲得以下錯誤信息:優化

消息 8622,級別 16,狀態 1,第 3 行
因爲此查詢中定義了提示,查詢處理器未能生成查詢計劃。請從新提交查詢,而且不要在查詢中指定任何提示,也不要使用 SET FORCEPLAN。ui

 

爲何SqlServer會產生這麼一個信息呢?spa

主要是由於查詢優化器在分析上面這個語句的時候發現了inner join的條件是code

a.id=b.idblog

而後又在where條件中發現了索引

a.id=@id1 and b.id=@id2hash

 

那麼在查詢優化器看來,@id1和@id2可能爲任何int類型的值,甚至有可能@id1=@id2,好比@id1=@id2=1it

那麼這個時候查詢優化器會認爲inner join徹底是多餘的,因此上面的語句就被查詢優化器優化爲了cross join的方式,以下方式,而後在這個結果上再作了a.id=1 and b.id=1的過濾io

select * 
from [dbo].[T_Peopl] a 
 cross join [dbo].[T_People_II] b

這個時候你去觀察上面這個語句的查詢計劃,發如今Nested Loops有一個紅色的小叉,表示這個join是沒有Predicate的,也就是沒有join條件的(Cross Join就沒有條件),術語叫非equijoin,實際上下面這個執行計劃中join兩邊的索引,只要有一邊沒有Predicate,那麼該join都是非equijoin。

 

而非equijoin是不能使用Merge/Hash join的,換句話說cross join是不能用Merge/Hash join的,只能用Loop join,因此最上面的那條語句會報錯,要求去掉option提示符。因此SqlServer的提示符不是何時均可以用的,甚至with(index(...))這種強制使用索引的提示符也不能隨便亂用,由於執行計劃中的某些步驟可能會和你聲明的提示符產生衝突,從而致使執行計劃生成失敗而報錯,要根據具體狀況具體分析合理使用各類SqlServer的提示符。

相關文章
相關標籤/搜索