繁体   English   中英

SQL子查询还是INNER-JOIN?

[英]SQL Sub-query or 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%

我thot子查询将是最佳的,因为子查询将在应用WHERE过滤器后执行。 统计数据表明查询#2 - JOIN方法更好。

请建议。 同样作为一个温和的SQL-Server用户,我如何能够更好地推导出哪个查询(除了执行计划之外的任何其他内容,如果它更有用)

谢谢。

join比子查询更快。

子查询使繁忙的磁盘访问,想到硬盘的读写指针(head?) ,它在访问时来回传递:User,SearchExpression,PageSize,DrilldownPageSize,User,SearchExpression,PageSize,DrilldownPageSize,User ...等等上。

join通过将操作集中在前两个表的结果上,任何后续连接都会集中连接到第一个连接表的内存(或缓存到磁盘)结果,依此类推。 较少的读写针运动,因此更快

你可以做的最好的事情是尝试两者并比较什么给你最好的表现。 很难再次猜测查询优化器将执行什么操作(您可以编写2个不同的查询,这些查询实际上最终会针对同一个执行计划进行优化)。

为了公平地比较性能,您应该确保通过在尝试每个执行计划和数据缓存之前清除执行计划和数据缓存从级别竞争领域尝试它们。 这可以使用以下命令完成,但只能在开发/测试数据库服务器上执行此操作:

DBCC FREEPROCCACHE
DBCC DROPCLEANBUFFERS

我通常采用的方法是运行每个查询3次,运行SQL事件探查器,这样我就可以监视查询的持续时间,读取,CPU和写入,然后我根据这些信息做出判断。

例如
1)使用上述命令清除缓存
2)运行查询和记录统计信息
3)清除缓存
4)再次运行查询
5)再次运行查询(这将使用缓存的执行计划/数据)

然后重复第二个查询进行比较。

它在很大程度上取决于数据的基数:如果你的内联查找与join大量数据的开销相比是最小的(当你只需要从该连接结果中提取一个小的子部分时),那么内联选项会更快。 但是如果你在内联选择中有很大的开销(即如果你的结果有很多行,而你正在为每一行调用一个内联选择),那么连接会更快。

我无法从你的问题中看到所涉及的数字(即多少行),因此很难做出定性评论。

例如,如果结果集有10行,则仅对这10行中的每一行执行内联选择,而连接可能涉及更多行,然后由WHERE子句选择性地减少。 但是如果你有一个1000万行的结果集,那么内联选择很可能会破坏性能,因为它是逐行的。

例子 :想象一下你必须从整个建筑场地收集一堆砖(由大小等指定)并将它们涂成蓝色。

内联选择 =选择所需的所有砖块,然后手工绘制。

join =将所有砖块倒入一大桶油漆中,然后选择你需要的油漆

如果你只想要10块砖,那么选择然后手工绘制要快得多。 如果你想要一百万块砖,那么首先在浴缸中进行大规模涂漆是可行的方法。

执行计划的相对成本并不总是可靠的绩效指标。

我假设你的SQL只返回1行。 假设UserId是User上的唯一键,那么在大多数关系数据库中,您的2种方法的性能将类似。

要记住的事情是:

  • 如果UserPreferences或SearchCriteria返回超过1行,第一种方法将引发sql错误,第二种方法将返回多于1行。
  • 第一种方法中明显的额外查找(UserPreferences选择两次)没有实际效果,因为对于第二次查找,记录已经在缓冲区中
  • 如果由于某种原因User表被扫描表空间,第一种方法会快得多

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM