如何在 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 以减少加载时间的主要内容,如果未能解决你的问题,请参考以下文章

SQL Server 内联查询是不是在后台创建临时表

如何检索 sql server 内联表值函数的返回值的元数据?

如何在sql server中将列转换为行

如何在 SQL Server 中将行动态转换为列

如何在 Sql Server Compact Edition 中将参数与 LIKE 一起使用

SQL Server 在执行期间是不是扩展视图的 sql 内联?