SqlServer 中使用Join提示的時候需要注意的一問題

來源:互聯網
上載者:User

標籤:

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

 

declare @id1 int=1,@id2 int=1select * from [dbo].[T_People] a  inner join [dbo].[T_People_II] b on a.id=b.idwherea.id=@id1 and b.id=@id2option(hash join)

我們在上面的查詢語句中使用了option提示符強制讓SqlServer使用Hash Join來做join查詢,在執行該語句時我們會得到如下錯誤資訊:

訊息 8622,層級 16,狀態 1,第 3 行
由於此查詢中定義了提示,查詢處理器未能產生查詢計劃。請重新提交查詢,並且不要在查詢中指定任何提示,也不要使用 SET FORCEPLAN。

 

為什麼SqlServer會產生這麼一個資訊呢?

主要是因為查詢最佳化工具在分析上面這個語句的時候發現了inner join的條件是

a.id=b.id

然後又在where條件中發現了

[email protected] and [email protected]

 

那麼在查詢最佳化工具看來,@id1和@id2可能為任何int類型的值,甚至有可能@[email protected],比如@[email protected]=1

那麼這個時候查詢最佳化工具會認為inner join完全是多餘的,所以上面的語句就被查詢最佳化工具最佳化為了cross join的方式,如下方式,然後在這個結果上再做了a.id=1 and b.id=1的過濾

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的提示符。

 

SqlServer 中使用Join提示的時候需要注意的一問題

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.