【问题标题】:Why is this TSQL sub-query slowing this query为什么这个 TSQL 子查询会减慢这个查询
【发布时间】:2013-06-06 09:28:25
【问题描述】:

我有一个查询,我需要加快速度:

    SELECT
Distinct Refs.SpecialtyReferredTo
FROM ABI_RiO.dbo.vwSGReferrals Refs
LEFT JOIN ABI_RiO.dbo.vwSGAppointmentsPD Apps ON Refs.ClientID = Apps. ClientID AND Refs.ReferralNumber = Apps.ReferralNumber
LEFT OUTER JOIN ABI_RiO.SchemaSG.AmsOutcome AS AOUT ON AOUT.Code=APPs.Outcome
LEFT JOIN ABI_RiO.SchemaSG.ClientIndex CI ON Refs.ClientID = CI.ClientID
LEFT JOIN ABI_RiO.SchemaSG.GenGPPractice GP ON GP.Code = CI.AIMTCCurrentGPPractice
where Refs.DischargeReason IS NULL
AND ((Apps.ContactID = ISNULL((SELECT Max(Apps2.ContactID)
FROM ABI_RiO.dbo.vwSGReferrals Refs2
LEFT JOIN ABI_RiO.dbo.vwSGAppointmentsPD Apps2 ON Refs2.ClientID = Apps2. ClientID AND Refs2.ReferralNumber = Apps2.ReferralNumber
LEFT OUTER JOIN ABI_RiO.SchemaSG.AmsOutcome AS AOUT ON AOUT.Code=APPs2.Outcome
WHERE Refs2.ClientID = Refs.ClientID
AND Refs2.ReferralNumber = Refs.ReferralNumber
AND NationalCode=5),
(SELECT Max(Apps2.ContactID)
FROM ABI_RiO.dbo.vwSGReferrals Refs2
LEFT JOIN ABI_RiO.dbo.vwSGAppointmentsPD Apps2 ON Refs2.ClientID = Apps2. ClientID AND Refs2.ReferralNumber = Apps2.ReferralNumber
WHERE Refs2.ClientID = Refs.ClientID
AND Refs2.ReferralNumber = Refs.ReferralNumber
))) OR Apps.ContactID IS NULL)
GROUP BY GP.Code, Refs.SpecialtyReferredTo

这需要永远执行。但是,如果我拆分查询的最后一部分,代码会在几秒钟内执行。即

     SELECT
Distinct GP.Code, Refs.SpecialtyReferredTo
FROM ABI_RiO.dbo.vwSGReferrals Refs
LEFT JOIN ABI_RiO.dbo.vwSGAppointmentsPD Apps ON Refs.ClientID = Apps. ClientID AND Refs.ReferralNumber = Apps.ReferralNumber
LEFT OUTER JOIN ABI_RiO.SchemaSG.AmsOutcome AS AOUT ON AOUT.Code=APPs.Outcome
LEFT JOIN ABI_RiO.SchemaSG.ClientIndex CI ON Refs.ClientID = CI.ClientID
LEFT JOIN ABI_RiO.SchemaSG.GenGPPractice GP ON GP.Code = CI.AIMTCCurrentGPPractice
where Refs.DischargeReason IS NULL
AND ((Apps.ContactID = ((SELECT Max(Apps2.ContactID)
FROM ABI_RiO.dbo.vwSGReferrals Refs2
LEFT JOIN ABI_RiO.dbo.vwSGAppointmentsPD Apps2 ON Refs2.ClientID = Apps2. ClientID AND Refs2.ReferralNumber = Apps2.ReferralNumber
LEFT OUTER JOIN ABI_RiO.SchemaSG.AmsOutcome AS AOUT ON AOUT.Code=APPs2.Outcome
WHERE Refs2.ClientID = Refs.ClientID
AND Refs2.ReferralNumber = Refs.ReferralNumber
AND NationalCode=5))))
GROUP BY GP.Code, Refs.SpecialtyReferredTo
ORDER BY GP.Code

这意味着我的问题出在查询的最后一部分:

 (SELECT Max(Apps2.ContactID)
FROM ABI_RiO.dbo.vwSGReferrals Refs2
LEFT JOIN ABI_RiO.dbo.vwSGAppointmentsPD Apps2 ON Refs2.ClientID = Apps2. ClientID AND Refs2.ReferralNumber = Apps2.ReferralNumber
WHERE Refs2.ClientID = Refs.ClientID
AND Refs2.ReferralNumber = Refs.ReferralNumber
))) OR Apps.ContactID IS NULL)
--GROUP BY GP.Code, Refs.SpecialtyReferredTo
--ORDER BY GP.Code

添加最后一个查询块会导致最终输出的数据扩展约 10%。

谁能帮我重新编写这个查询并解释为什么最后一部分会导致执行性能如此下降。 干杯。

R

【问题讨论】:

    标签: performance tsql subquery


    【解决方案1】:

    我在这里的第一个倾向是将 ISNULL 部分中的相关子查询更改为两个获取这些值的 OUTER APPLY 计算。

        SELECT
    DISTINCT    Refs.SpecialtyReferredTo
        FROM    ABI_RiO.dbo.vwSGReferrals Refs
        LEFT JOIN ABI_RiO.dbo.vwSGAppointmentsPD Apps
        ON      Refs.ClientID = Apps.ClientID
                AND Refs.ReferralNumber = Apps.ReferralNumber
        LEFT OUTER JOIN ABI_RiO.SchemaSG.AmsOutcome AS AOUT
        ON      AOUT.Code = APPs.Outcome
        LEFT JOIN ABI_RiO.SchemaSG.ClientIndex CI
        ON      Refs.ClientID = CI.ClientID
        LEFT JOIN ABI_RiO.SchemaSG.GenGPPractice GP
        ON      GP.Code = CI.AIMTCCurrentGPPractice
    OUTER APPLY (select max(Apps2.ContactID) as ContactID1 ...) as OuterApply1
    OUTER APPLY (select max(Apps2.ContactID) as ContactID2 ...) as OuterApply2
        WHERE   Refs.DischargeReason IS NULL
    AND (Apps.ContactID = ISNULL(ContactID1, ContactID2) or Apps.ContactID IS NULL )
    

    一般而言,当您尝试为每一行计算该相关子查询时,该相关子查询会导致性能问题。将这些计算切换到 OUTER APPLY 至少可以让您将它们作为一组进行处理。

    这里有一些 OUTER APPLY 的例子:http://www.mssqltips.com/sqlservertip/1958/sql-server-cross-apply-and-outer-apply/ 在这里:https://www.simple-talk.com/sql/t-sql-programming/sql-server-apply-basics/

    【讨论】:

    • 谢谢彼得 - 我不熟悉这种方法。在我进步之前,我会阅读文章。
    • 嗨彼得 - 我决定在应用上述解决方案之前完全解构查询(这是由我不熟悉的数据库上的前同事编写的)。这样做时,我注意到外部选择实际上检索到与相关子查询 PLUS 外部选择完全相同的值,并且外部选择在大约一秒钟内自行实现了我的目的,所以我将坚持下去。不过,我查看了您建议的文章,并且学到了一些我以前不知道的知识,因此为此欢呼。 R.
    猜你喜欢
    • 2011-05-26
    • 1970-01-01
    • 2011-03-11
    • 2011-10-18
    • 2020-03-19
    • 2014-03-12
    • 2011-02-28
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多