实际执行计划中的最高成本部分没有显示任何逻辑读取?

Syl*_*via 2 performance sql-server

在下面的查询计划 - https://www.brentozar.com/pastetheplan/?id=H1dwOCHed(它有 3 个部分,最后一个是问题),最底部有一个节点,消耗了 37% 的资源. 这是实际的查询计划,而不是估计的查询计划。但是,当通过 Set Statistics IO 查看逻辑读取时,它引用的表根本不显示。这包括 ActivityFeedTeamCache 和 ActivityFeedCache 的 2 个部分。

过去,我已经能够使用逻辑读取作为性能的一个很好的代理。减少逻辑读取,您就为性能做了正确的事情。

但是,由于在这种情况下,对于最差的块(ActivityFeedTeamCache、ActivityFeedCache、Locales)没有逻辑读取,那么什么是测试性能的好代理?仅仅是实际执行计划中的成本百分比下降了吗?

And*_*yer 6

即使在实际执行计划中,成本百分比仍然只是一个估计值。您需要查看此处的行源级别统计信息,以告诉您每个步骤花费了多少时间。

从 XML 来看,274 毫秒到节点 7 的散列连接点,其中 72 毫秒只是Pk_TeamMembers(节点 8)的集群扫描,35 毫秒到左半连接(节点 9)。这意味着仅执行 Hash Join 步骤就花费了惊人的 167 毫秒(可能为 263,600 行分配内存Pk_TeamMembers)。

看起来您之前已经尝试过定位此连接:

LEFT JOIN TeamMembers tm on AF.CompletionUserID = tm.UserID AND AF.TeamID = tm.TeamID AND tm.TeamID = t.TeamID -- Overloaded to help SQL find indexes
Run Code Online (Sandbox Code Playgroud)

您可能希望对此索引执行(外部)嵌套循环。查询规划器决定使用散列连接,因为它认为您将从该连接的另一侧获得 59000 行,而实际上您获得 3。

你有选择

  • 提示以便使用嵌套循环连接
  • 找出为什么规划器认为它会有这么多行并给它一些帮助(统计,简化过滤)

提示看起来像

LEFT LOOP JOIN TeamMembers tm on AF.CompletionUserID = tm.UserID AND AF.TeamID = tm.TeamID AND tm.TeamID = t.TeamID
Run Code Online (Sandbox Code Playgroud)

由于驾驶过滤器的复杂性,第二个选择将特别困难。一种方法是插入与您的主要驱动过滤器匹配的行,然后在您的主查询中加入这个临时表。在这里,您似乎需要先将 5 个表中的 3 个连接在一起才能@userId@公平地利用您的过滤器:

FROM ActivityFeed AF
    JOIN ActivityType A ON AF.ActivityType = A.ActivityType
    LEFT JOIN Teams t on AF.TeamID = t.TeamID
WHERE 
    AF.SearchIndexUpdateDate IS NULL -- Only get items that aren't in the search index
    AND
    AF.Active=1 
    AND 
    A.Active=1
    AND
    (A.AdminOnly = 0 OR AF.TeamID IN (SELECT TeamID FROM @tmpFindAdminFlagsForTeamsMembershipsForUser x WHERE x.IsAdmin=1))
    AND
    ( 
      (
        A.TeamOnly=1 
        AND AF.TeamID IN (SELECT TeamID FROM @tmpFindAdminFlagsForTeamsMembershipsForUser x WHERE A.HideWhenOwnerless = 0 OR x.IsOwnerless = 0)
        AND (A.ShowSelf=1 OR AF.CompletionUserID <> @UserID)
        AND ISNULL(t.IsDeleted,0) = 0 AND t.active=1
        AND (A.IncludeOnsite = 1 OR EXISTS(SELECT 1 FROM @tmpFindAdminFlagsForTeamsMembershipsForUser x WHERE x.TeamID = AF.TeamID AND x.IsOnsiteOwner = 0))
       )
       OR 
      (
        A.UserOnly=1 
        AND AF.UserID=@UserID
      )
    )
    AND
    -- Don't included moderated activity (owner moderation actions are in Group activity view API_GetActivityFeedByTeam)
    AF.Moderated = 0 
    AND
   -- don't show completions or plan completions to other team members if opted out (tm.ShowUserActivityInFeed)
    (ISNULL(A.ShowOnlyWhenUserActivityActive,0) = 0 OR (A.ShowOnlyWhenUserActivityActive = 1 AND tm.ShowUserActivityinFeed = 1))
    AND
    (AF.TeamID IS NULL OR AF.TeamID IN (SELECT TeamID FROM @tmpFindAdminFlagsForTeamsMembershipsForUser as x))
Run Code Online (Sandbox Code Playgroud)