【问题标题】:SQL Sub-query or INNER-JOIN?SQL 子查询还是 INNER-JOIN?
【发布时间】:2010-12-19 19:24:26
【问题描述】:

我有以下两个查询:

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 过滤器之后执行。统计数据表明 Query#2 - JOIN 方法更好。

请建议。同样作为一个适度的 SQL-Server 用户,我怎样才能得出哪个查询更好(除执行计划之外的任何其他内容,如果它更有帮助的话)

谢谢。

【问题讨论】:

  • -- 查询 #3:完成 LEFT OUTER JOIN-query SELECT u.[Id] , u.[Name] , u.[OrgId] AS Organization, u.OrgId As OrgId, o.[ Name] As OrganizationName, u.[UserRoleId] AS UserRole, u.[UserCode] AS UserCode, u.[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 LEFT OUTER JOIN [Org] as o ON o.Id = u.OrgId WHERE ISNULL(sc.IsDefault,1)=1 AND u.Id = @UserId

标签: sql-server performance sql


【解决方案1】:

join 比子查询快。

子查询导致繁忙的磁盘访问,想想硬盘的读写针(头?)在访问时来回走动:User、SearchExpression、PageSize、DrilldownPageSize、User、SearchExpression、 PageSize、DrilldownPageSize、User...等等。

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

【讨论】:

    【解决方案2】:

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

    我从您的 sql 中假设应该只返回 1 行。如果 UserId 是 User 上的唯一键,那么您的 2 种方法的性能在大多数关系数据库上将是相似的。

    要记住的事情是:

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

    【讨论】:

      【解决方案3】:

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

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

      例如,如果您的结果集有 10 行,则将仅对这 10 行中的每一行执行内联选择,而连接可能涉及更多行,然后通过 WHERE 子句选择性地减少这些行。但是,如果您有 1000 万行的结果集,则内联选择很可能会降低性能,因为它是逐行的。

      示例:假设您必须从建筑院子各处收集一堆砖块(按尺寸等指定)并将它们涂成蓝色。

      内联选择 = 选择您需要的所有积木,然后手工绘制它们。

      加入 = 将所有砖块倒入一个巨大的油漆桶中,然后选择你需要的那些

      如果您只想得到 10 块积木,则选择然后手工绘制要快得多。如果你想要一百万块砖,那么首先在浴缸中大量绘制它们是可行的方法。

      【讨论】:

      • 我知道这个答案是很久以前的事了,但事实上内联选择语句是针对返回的行在线执行的,而不是针对整个查询。如果查询被包装在 MSSQL 中以进行分页,这仍然是正确的,例如在这个例子中:stackoverflow.com/questions/8059282/…
      【解决方案4】:

      您可以做的最好的事情是尝试两者并比较什么可以为您带来最佳性能。很难猜测查询优化器会做什么(您可以编写 2 个不同的查询,实际上最终会针对相同的执行计划进行优化)。

      为了公平地比较性能,您应该确保在一个公平的竞争环境中尝试它们,方法是在尝试每一个之前清除执行计划和数据缓存。这可以使用以下命令完成,但只能在开发/测试数据库服务器上执行:

      DBCC FREEPROCCACHE
      DBCC DROPCLEANBUFFERS
      

      我通常采用的方法是运行每个查询 3 次,同时运行 SQL Profiler,这样我就可以监控查询的持续时间、读取、CPU 和写入,然后我会根据这些查询做出决定。

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

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

      【讨论】:

        猜你喜欢
        • 2014-02-24
        • 1970-01-01
        • 1970-01-01
        • 2015-01-10
        • 1970-01-01
        • 2012-11-04
        • 2017-12-21
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多