2015-09-11 37 views
4

我知道有很多這些問題,但我找不到與我的問題有關的問題。select top 1 * vs select top 1 1

望着這個問題,Is Changing IF EXIST(SELECT 1 FROM) to IF EXIST(SELECT TOP 1 FROM) has any side effects?

具體指的是在回答本節:

select * from sys.objects 
select top 1 * from sys.objects 
select 1 where exists(select * from sys.objects) 
select 1 where exists(select top 1 * from sys.objects) 

我跑我自己的一些測試,以正確地理解它。正如在答覆中指出:

select 1 where exists(select top 1 * from sys.objects) 
select 1 where exists(select top 1 1 from sys.objects) 

都引起相同的執行計劃,也使得同樣的計劃,

select 1 where exists(select * from sys.objects) 
select 1 where exists(select 1 from sys.objects) 

從我的研究,像這樣的,「SELECT TOP 1 1」 VS 「IF EXISTS(SELECT 1」問題。我推斷,這是約定最佳實踐:

select 1 where exists(select * from sys.objects) 

我的第一個問題是,爲什麼是這個優於此:

select 1 where exists(select 1 from sys.objects) 

在試圖理解它,我打破了下來,他們更基本表達式(我使用「頂部1」,以模仿執行計劃外形酷似存在):

select top 1 * from sys.objects 
select top 1 1 from sys.objects 

我現在看到的是,第一是80%的執行時間(相對於批2),而第二個是20%。難道再沒有更好的做法是使用

select 1 where exists(select 1 from sys.objects) 

,因爲它可以適用於這兩種方案,從而減少可能的人爲錯誤?

+0

注:在這裏有一個很好的寫作:http://www.sqlservercentral.com/articles/T-SQL/154149/ – JohnLBevan

+0

是的,我也剛剛閱讀這篇文章,這是一個權威的測試。因爲null在CPU和內存之間使用了一個指針,所以當使用null而不是*或者1來完成時,我很想找時間來測試他的結果。 – Storm

回答

7

SQL Server檢測EXISTS謂詞在查詢編譯/優化過程的比較早,並消除了實際的數據檢索了這樣的條款,以檢查是否存在替換他們。所以你的假設:

I now see that the first is 80% of the execution time (relative to the batch of 2) whilst the second is only 20%.

是錯誤的,因爲在前面的比較,你實際上已經獲取一些數據,如果查詢被放入(not) exists斷言這不會發生。

大部分時間裏,沒有任何區別如何測試行的存在,除了單個但重要的漁獲物。假設你說:

if exists (select * from dbo.SomeTable) 
... 

代碼模塊(視圖,存儲過程,函數等)的某處。然後,後來,別人什麼時候決定把WITH SCHEMABINDING條款到這個代碼模塊,SQL Server將不允許和它,而不是可能結合當前的列清單,將引發錯誤:

Msg 1054, Level 15, State 7, Procedure BoundView, Line 6
Syntax '*' is not allowed in schema-bound objects.

所以,總之:

if exists (select 0 from ...) 

是一種最安全,最快速和一刀切的存在檢查方式。

+0

我真的很喜歡這個答案,因爲'WITH SCHEMABINDING'信息爲這絕對是一個巨大的遊戲改變者,並且是'SELECT 1'與'SELECT *'的最佳參數。你可能有一個鏈接到一個參考周圍呢? – Storm

+0

嗯,我只聽說過這樣的漏洞,真相被告知。現在我已經自己對它進行了測試,SQL Server不允許你通過拋出錯誤1054來拍攝自己的腿,「在綁定模式的對象中不允許使用Syntax'*'。」這使得我的論點有些微弱,儘管如此作爲一種萬能的方法是有效的。哦,是的,我在2012版中遇到了這個錯誤 - 不知道老年人會如何迴應。 –

3

這兩者之間的區別:

select top 1 * from sys.objects 
select top 1 1 from sys.objects 

是第一個子句中的SQL服務器必須從表中獲取所有的列(從任何隨機行),但在第二個它取只是OK「 1「來自任何索引。

當這些子句位於exists子句中時,事情會發生變化,因爲在這種情況下,SQL Server知道它實際上並不需要獲取數據,因爲它不會被分配給任何東西,所以它可以像處理select *一樣將處理select 1

既然存在檢查只有一行,它內置頂部1,所以手動添加它不會改變任何東西。

天氣有select *select 1在存在的條款是基於意見,而不是1你當然可以有2或'X'或任何你喜歡的。我個人一直使用... and exists (select 1 ...

+0

謝謝,我明白了(大部分都在我的操作中)。我的問題是圍繞着爲什麼一個是優先於另一個(因爲它們嵌套在和'EXIST'語句中時它們在語義上是相同的)。對我來說,似乎'SELECT 1'似乎是'更安全的一般經驗法則',特別是當建議技術顧問誰不研究SQL作爲職業 – Storm

1

EXISTS是一種類型的子查詢只能返回基於是否有任何行由子查詢返回的布爾值。選擇1或*,或者在此上下文中無關緊要,因爲結果總是正確或錯誤。

您可以通過測試這兩個語句產生完全相同的計劃來驗證這一點。

select 1 where exists(select * from sys.objects) 
select 1 where exists(select 1 from sys.objects) 

您在外部查詢中選擇的內容確實重要。當你發現,這兩個語句產生非常不同的執行計劃:

select top 1 * from sys.objects 
select top 1 1 from sys.objects 

第一個會慢一些,因爲它實際返回的真實數據。在這種情況下,加入三個基礎表:syspalnames,syssingleobjrefs和sysschobjs。

至於你把你的EXISTS子查詢裏面的偏好 - 選擇1或SELECT * - 沒關係。我通常說SELECT 1,但SELECT *同樣好,你會在很多微軟文檔中看到它。

0

我一直在尋找包含在標題的答案只是實際問題。我發現它at this link

Select Top 1 or Top n basically returns the first n rows of data based on the sql query. Select Top 1 1 or Top n s will return the first n rows with data s depending on the sql query.

For example, the query below produces the first name and last name of the first 10 matches. This query will return first name and last name only.

SELECT TOP 10 FirstName, LastName 
    FROM [tblUser] 
    where EmailAddress like 'john%' 

Now, look at this query with select top 10 'test' - this will produce the same number of rows as in the previous query (same database, same condition) but the values will be 'test'.

SELECT TOP 10 'test' 
    FROM [tblUser] 
    where EmailAddress like 'john%' 

所以,select TOP 1 *返回第一行,而select TOP 1 1返回一個一行只包含 「1」。這個如果查詢返回至少一行,否則返回Null will be returned in both cases

作爲附加的例子,這樣的:

SELECT TOP 10 'test', FirstName 
    FROM [tblUser] 
    where EmailAddress like 'john%' 

將返回含有填充有「測試」並填充有查詢的第一10場比賽的第一名字的另一列一列的表。