2009-11-24 130 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)表观额外的查找没有实际的效果,因为对于第二查找记录将已经在缓冲器
  • 如果由于某种原因用户表的表空间进行扫描,所述第一种方法将更快