如何在 SQL SERVER 中将内联 SQL 查询转换为 JOINS 以减少加载时间

Posted

技术标签:

【中文标题】如何在 SQL SERVER 中将内联 SQL 查询转换为 JOINS 以减少加载时间【英文标题】:How to convert inline SQL queries to JOINS in SQL SERVER to reduce load time 【发布时间】:2021-12-26 04:21:56 【问题描述】:

我需要帮助来优化这个 SQL 查询。

SELECT 主语句中,有三列取决于外部查询结果。这就是为什么我的查询需要很长时间才能返回数据。我曾尝试进行左连接,但这不能正常工作。

谁能帮我解决这个问题?

SELECT 
  DISTINCT ou.OrganizationUserID AS StudentID, 
  ou.FirstName, 
  ou.LastName, 
  (
    SELECT 
      STRING_AGG(
        (ug.UG_Name), 
        ','
      ) 
    FROM 
      Groups ug 
      INNER JOIN ApplicantUserGroup augm ON augm.AUGM_UserGroupID = ug.UG_ID 
    WHERE 
      augm.AUGM_OrganizationUserID = ou.OrganizationUserID 
      AND ug.UG_IsDeleted = 0 
      AND augm.AUGM_IsDeleted = 0
  ) AS UserGroups, 
  order1.OrderNumber AS OrderId -- UAT-2455         
  , 
  (
    SELECT 
      STRING_AGG(
        (CActe.CustomAttribute), 
        ','
      ) 
    FROM 
      CustomAttributeCte CActe 
    WHERE 
      CActe.HierarchyNodeID = dpm.DPM_ID 
      AND CActe.OrganizationUserID = ps.OrganizationUserID
  ) AS CustomAttributes -- UAT-2455
  , 
  (
    SELECT 
      STRING_AGG(
        (CActe.CustomAttributeID), 
        ','
      ) 
    FROM 
      CustomAttributeCte CActe 
    WHERE 
      CActe.HierarchyNodeID = dpm.DPM_ID 
      AND CActe.OrganizationUserID = ps.OrganizationUserID
  ) AS CustomAttributeID 
FROM 
  ApplicantData acd WITH (NOLOCK) 
  INNER JOIN ClientPackage ps WITH (NOLOCK) ON acd.ClientSubscriptionID = ps.ClientSubscriptionID 
  INNER JOIN [ClientOrder] order1 WITH (NOLOCK) ON order1.OrderID = ps.OrderID 
  AND order1.IsDeleted = 0 
  INNER JOIN OUser ou WITH (NOLOCK) ON ou.OrganizationUserID = ps.OrganizationUserID

【问题讨论】:

mysql“SQL Server”?这些是完全不同的数据库。更新不正确的标签/文本。 @user2864740,问题基本和SQL SERVER有关 然后从标签中删除“mysql”。 为了获得性能帮助,您必须包括表索引定义,以及共享查询计划(您可以通过brentozar.com/pastetheplan )。没有这些信息,这是无法回答的。为什么你有NOLOCK,你知道它是做什么的吗,你有你想要解决的阻塞问题吗?它不是一个更快的开关,它是一个给出不正确结果的开关,并且可能导致比它解决的问题更多 您可以在单个APPLY 中执行第二个和第三个STRING_AGG,以避免对该表进行两次查询。为什么DISTINCT 在那里,我怀疑这可能是您的主要问题,您是否有要删除的重复项?如果是这样,为什么会有重复,哪个连接导致它们? 【参考方案1】:

看起来这个查询可以简化,并且删除 SELECT 子句中的依赖子查询,考虑你的第二个和第三个依赖子查询。您可以使用 LEFT JOIN 将它们重构为一个不相关的子查询。使用非依赖子查询效率更高,因为查询计划器可以只运行一次,而不是每行运行一次。

您需要来自同一个表的两个 STRING_AGG() 结果。此子查询为HierarchyNodeIDOrganizationUserID 值的每个可能组合提供这两个输出。 STRING_AGG() 是一个类似于 SUM() 的聚合函数,因此可以很好地与 GROUP BY 配合使用。

      SELECT HierarchyNodeID, OrganizationUserID,
             STRING_AGG((CActe.CustomAttribute), ',') CustomAttributes -- UAT-2455,
             STRING_AGG((CActe.CustomAttributeID), ',') CustomAttributeIDs -- UAT-2455
        FROM CustomAttributeCte CActe
       GROUP BY HierarchyNodeID, OrganizationUserID

您可以自己运行这个子查询来说服自己它有效。

现在,我们可以将其加入到您的查询中。像这样。 (为了可读性,我去掉了 NOLOCK 并使用了 JOIN:它与 INNER JOIN 的含义相同。)

SELECT DISTINCT 
       ou.OrganizationUserID AS StudentID,
       ou.FirstName,
       ou.LastName,
       'tempvalue' AS UserGroups,  -- shortened for testing
       order1.OrderNumber AS OrderId, -- UAT-2455
       uat2455.CustomAttributes,      -- UAT-2455
       uat2455.CustomAttributeIDs     -- UAT-2455
  FROM ApplicantData acd
  JOIN ClientPackage ps 
               ON acd.ClientSubscriptionID = ps.ClientSubscriptionID
  JOIN ClientOrder order1 
               ON order1.OrderID = ps.OrderID
              AND order1.IsDeleted = 0
  JOIN OUser ou
               ON ou.OrganizationUserID = ps.OrganizationUserID
  LEFT JOIN (
      SELECT HierarchyNodeID, OrganizationUserID,
             STRING_AGG((CActe.CustomAttribute), ',') CustomAttributes -- UAT-2455,
             STRING_AGG((CActe.CustomAttributeID), ',') CustomAttributeIDs -- UAT-2455
        FROM CustomAttributeCte CActe
       GROUP BY HierarchyNodeID, OrganizationUserID
     ) uat2455 
               ON uat2455.HierarchyNodeID = dpm.DPM_ID
              AND uat2455.OrganizationUserId = ps.OrganizationUserID

看看我们如何将您的第二个和第三个依赖子查询折叠成一个,然后将其用作具有 LEFT JOIN 的虚拟表?我们将 WHERE 子句从依赖子查询转换为 ON 子句。

您可以对此进行测试:使用 TOP(50) 运行它并观察结果。

当您满意时,下一步就是以同样的方式转换您的第一个依赖子查询。

专业提示永远不要使用WITH (NOLOCK),除非数据库管理专家在查看您的特定查询后告诉您。如果您的查询的目的是历史报告,并且您不关心数据库中的最新交易是否完全正确,您可以在查询之前使用此语句。它还允许查询在避免锁定的同时运行。

SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;

专业提示 着迷于格式化查询以提高可读性。一年后,您、您的同事和您自己必须能够阅读和推理此类查询。

【讨论】:

以上是关于如何在 SQL SERVER 中将内联 SQL 查询转换为 JOINS 以减少加载时间的主要内容,如果未能解决你的问题,请参考以下文章