關於T-SQL中exists或者not exists子查詢的“偽優化”的做法


 

問題起源

在使用t-sql中的exists(或者not exists)子查詢的時候,不知道什么時候開始,發現一小部分人存在一種“偽優化”的一些做法,
並且向不明真相的群眾傳遞這一種寫法“優越性”,實在看不下去,
無法傳遞給他人正確的指導思想無可厚非,給他人傳遞錯誤的思想或者說誤導人倒是一種罪惡。
本來這個事情是不值得一提的,看到越來越多被誤導的群眾開始推崇這種做法(甚至開始堅信了),實在是看不習慣,不吐不快。
典型的問題如下
select * from TableA a
where exists
(select 1 from TableB b where a.Id = b.Id ),當然這里子查詢里寫成select * 也無所謂。
這個要表達的邏輯就是說B表中存在與A表相同的Id的數據,就成立,這是要表達的邏輯。
參考如下寫法,有人偏偏在在exists子查詢中加上top 1 1,問其原因,為什么提高性能?理由就是加了top 1 1,只要在TableB中存在一條滿足條件的條件即可,同時不用返回所有的行和列,因此可以提高性能。
select * from TableA a
where exists
(select top 1 1 from TableB b where a.Id = b.Id )
與直接寫select 1 from TableB where a.Id =b.Id相比,真的可以提高性能嗎?

 

  exists(或者not exists)子查詢的實現是一種半連接的“探測”邏輯機制(Semi Join),意思就是只要存在(而不關心具體有多少條)符合條件的數據即可,當然是不會再B表中找到所有的數據行(或者列)之后再返回。
  但是exists(或者not exists)具體在執行的時候,到底走不走Semi Join不一定,跟具體的執行計划有關,本文暫不討論走不走Semi Join的問題,只討論子查詢中select top 1 1 的寫法到底影不影響效率。

 

測試驗證

就以AdventureWorks2012示例庫的兩個表做demo,看看兩者的執行計划和IO信息,會發現子查詢中加不加 top  1,執行計划一樣,IO一樣,扯什么性能……

  exists(或者not exists)的半連接的邏輯機制(Semi Join)決定了,你寫不寫top 1,它都是找到一個符合條件的數據之后就返回外層查詢,
  甚至在子查詢中寫select * from TableName,如果走Semi Join的執行方式,他照樣是探測到有一條存在的數據之后就返回,肯定不會把所有的行都給找出來再返回,
  以下截圖可以看到,即便子查詢是select * ,IO信息也是一樣的(當然執行計划也一樣)。
  在當前這種情況下,可以認為exists子查詢中的*,也是不會影響效率什么的。

  甚至是可以在子查詢中select一個常量,也不會影響到效率或者說改變執行計划。

  

 

總結

  這個問題比較簡答,當然這個場景也僅限於sqlserver中的exists或者not exists子查詢,對於別的數據庫也不確定是不是優化器內部會自動優化。
  當前這種場景下,對於sqlserver來說,不要費盡心思去刻意用select top 1 1去“優化”了。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM