2009-11-24 212 views
4

我有兩個以下查詢:SQL子查詢或INNER-JOIN?

declare @UserId as int 
set @UserId = 1 

-- Query #1: Sub-query 
SELECT 
    u.[Id] , 
    u.[Name] , 
    u.[OrgId] AS Organization, 
    (SELECT o.[Name] FROM Org o WHERE o.Id = u.OrgId) As OrganizationName, 
    [UserRoleId] AS UserRole, 
    [UserCode] AS UserCode, 
    [EmailAddress] As EmailAddress, 
    (SELECT SearchExpression FROM SearchCriteria WHERE UserId = @UserId AND IsDefault=1) AS SearchCriteria, 
    (SELECT PageSize FROM UserPreferences WHERE UserId = @UserId) AS UserPreferencePageSize, 
    (SELECT DrilldownPageSize FROM UserPreferences WHERE UserId = @UserId) AS UserPreferenceDrilldownPageSize 
    FROM [User] as u 
WHERE u.Id = @UserId 

-- Query #2: LEFT OUTER JOIN-query 
SELECT 
    u.[Id] , 
    u.[Name] , 
    u.[OrgId] AS Organization, 
    (SELECT o.[Name] FROM Org o WHERE o.Id = u.OrgId) As OrganizationName, 
    [UserRoleId] AS UserRole, 
    [UserCode] AS UserCode, 
    [EmailAddress] As EmailAddress, 
    sc.SearchExpression As SearchExpression, 
    up.PageSize As PageSize, 
    up.DrilldownPageSize As DrilldownPageSize  
    FROM [User] as u 
LEFT OUTER JOIN [UserPreferences] as up ON u.id = up.UserId 
LEFT OUTER JOIN [SearchCriteria] as sc ON u.id = sc.UserId 
    WHERE ISNULL(sc.IsDefault,1)=1 AND u.Id = @UserId 

查詢執行計劃的統計:(相對於批次查詢成本)

  • 查詢#1(子查詢):56%
  • 查詢#2(加入):44%

我打算子查詢將是最優的,因爲子查詢將在執行後應用WHERE過濾器。統計數據表明查詢#2 - JOIN方法更好。

請建議。作爲一個適度的SQL服務器用戶,我怎樣才能得出哪個查詢更好(除了執行計劃之外的任何其他執行計劃,如果它更有幫助)

謝謝。

+0

- 查詢#3:完全LEFT OUTER JOIN查詢 選擇 \t U [ID], \t U [名], \t U [ORGID] AS。組織, \t u.OrgId作爲ORGID, O操作。[名]作爲單位名稱, \tü。[UserRoleId] AS的UserRole, \tü。[USERCODE] AS USERCODE, \tü。[EmailAddress的作爲EmailAddress的,\t \t sc.SearchExpression As SearchExpression, \t up.PageSize由於PageSize, \t up。DrilldownPageSize作爲DrilldownPageSize \t FROM [用戶]爲u LEFT OUTER JOIN [使用UserPreferences]至多ON u.id = up.UserId 左外連接[SearchCriteria如SC ON u.id = sc.UserId LEFT OUTER JOIN [ Org] as o ON o.Id = u.OrgId \t WHERE ISNULL(sc.IsDefault,1)= 1 AND u.Id = @UserId – 2009-11-24 08:59:02

回答

10

聯接比子查詢更快。

子查詢,使忙碌的磁盤訪問,認爲硬盤的讀寫針可以追溯到來回,當它進入(頭):用戶,SearchExpression,每頁,DrilldownPageSize,用戶,SearchExpression,每頁,DrilldownPageSize,用戶...等等。

加入作品通過集中對前兩個表結果的操作,任何後續連接都將集中連接到第一個連接表的內存(或緩存到磁盤)結果,等等。少讀寫指針移動,從而更快

1

它將在很大程度上取決於數據的基數:如果您的內聯查找相對於大量數據的開銷(當您只需從該連接結果中提取一個小部分)那麼內聯選項會更快。但是,如果您在線選擇時有大量開銷(即,如果結果中有大量行,並且您爲每行調用了內聯選擇),那麼聯接將更快。

我從你的問題中看不到涉及的數字(即多少行),因此很難做出定性評論。例如,如果您的結果集有10行,那麼僅對這10行中的每一行執行行內選擇,而連接可能涉及更多的行,然後通過WHERE子句選擇性地減少行。但是如果你有一個1000萬行的結果集,內聯選擇很可能會導致性能下降,因爲它是逐行的。

示例:想象一下,您必須從建築工地的各處收集大量磚塊(由尺寸等指定)並將它們塗成藍色。

內聯選擇 =選擇您需要的所有磚塊,然後用手繪製它們。

加入 =轉儲所有的磚到油漆的一個巨大的水桶,ANF然後選擇你需要

如果你只想用10塊磚結束了的,它是遠遠快於選擇後再搽用手。如果你想要一百萬塊磚,那麼首先將它們大量塗抹在浴缸中是一條可行的路。

+0

我知道這個答案相當一段時間以前,但事實上,內聯select語句在線執行返回的行,而不是整個查詢。如果查詢被包裝在MSSQL中進行分頁,例如在這個例子中,這仍然是真的:http://stackoverflow.com/questions/8059282/which-is-faster-a-select-sub-query-or-a-left - 外聯接-IN-A-分頁對結果本身 – Nucleon 2011-11-09 05:47:02

4

您可以做的最好的事情就是嘗試兩種方法,並比較一下爲您提供的最佳性能。很難再次猜測查詢優化器會做什麼(您可以編寫2個不同的查詢,實際上最終會針對相同的執行計劃進行優化)。

爲了公平地比較性能,您應該確保您在嘗試每個平臺之前清理執行計劃和數據高速緩存,以確保您在公平競爭環境中嘗試它們。這可以用下面的命令來完成,雖然只是做一個開發/測試數據庫服務器上:

DBCC FREEPROCCACHE 
DBCC DROPCLEANBUFFERS 

我通常採用的方法是運行每個查詢3次,用SQL Profiler運行,所以我可以監控持續時間,讀取,CPU和寫入的查詢,然後我根據我的決定。

例如
1),使用清除緩存命令
2)運行查詢和記錄統計
3)清除緩存
4)運行查詢再次
再次5)運行的查詢(這將使用緩存執行計劃/數據)

然後重複第二個查詢進行比較。

1

執行計劃的相對成本並不總是可靠的性能指標。

我假設你的sql只有1行應該返回。如果UserId是用戶的唯一鍵,那麼在大多數關係數據庫中,您的兩種方法的性能將會類似。

事牢記是:

  • 如果使用UserPreferences或SearchCriteria返回超過1行,第一種方法會拋出一個SQL錯誤,第二個方法將返回超過1行。
  • 在第一種方法(選擇兩次使用UserPreferences)表觀額外的查找沒有實際的效果,因爲對於第二查找記錄將已經在緩衝器
  • 如果由於某種原因用戶表的表空間進行掃描,所述第一種方法將更快