SQL Server查询缓慢-如何进行优化?

时间:2019-06-05 04:12:31

标签: sql sql-server sql-server-2017

我希望获得一些帮助来优化此查询以使其更快。

此查询产生一个视图,该视图将显示在网站的表格中。 这个查询很慢,我正在尝试使其更快。

到目前为止,我唯一尝试做的就是减少为表检索的列数。

这是查询:

SELECT        TOP (100) PERCENT Id, MAX(BusinessTitle) AS BusinessTitle, MAX(ClientName) AS ClientName, MAX(ClientType) AS Type, MAX(CreatedWhen) AS CreatedWhen, MAX(CASE WHEN C.[CreatedBy] IS NULL 
                     THEN 'Client' ELSE 'Admin' END) AS CreatedBy, CAST(MAX(CASE WHEN C.IsDisabled = 1 THEN 1 ELSE 0 END) AS BIT) AS IsDisabled, MAX(ReferenceSource) AS ReferenceSource, MAX(OtherReferenceSource) 
                     AS OtherReferenceSource, MAX(Address) AS Address,
                         (SELECT        MAX(T.FirstName + ' ' + T.LastName) AS Expr1
                           FROM            dbo.ApplicationUsers AS A INNER JOIN
                                                     dbo.Therapists AS T ON A.UserName = MAX(C.ClientName) AND A.Id = T.ApplicationUserId) AS ClientAdmin,
                         (SELECT        MAX(A.Email) AS Expr1
                           FROM            dbo.ApplicationUsers AS A INNER JOIN
                                                     dbo.Therapists AS T ON A.UserName = MAX(C.ClientName) AND A.Id = T.ApplicationUserId) AS Email,
                         (SELECT        MAX(Name) AS Expr1
                           FROM            dbo.Cities AS CY
                           WHERE        (Id = MAX(C.CityId))) AS City,
                         (SELECT        COUNT(*) AS Expr1
                           FROM            dbo.Patients AS P
                           WHERE        (ClientId = C.Id)) AS TotalPatientCount,
                         (SELECT        COUNT(*) AS Expr1
                           FROM            dbo.Patients AS P
                           WHERE        (ClientId = C.Id) AND (IsDeleted = 0) AND (IsDisabled = 0)) AS ActivePatientCount,
                         (SELECT        MAX(CreatedWhen) AS Expr1
                           FROM            dbo.Patients AS P
                           WHERE        (ClientId = C.Id)) AS LastPatientAddition,
                         (SELECT        COUNT(*) AS Expr1
                           FROM            dbo.Treatments AS T
                           WHERE        (ClientId = C.Id)) AS TotalTreatmentCount,
                         (SELECT        MAX(CreatedWhen) AS Expr1
                           FROM            dbo.Treatments AS T
                           WHERE        (ClientId = C.Id)) AS LastTreatmentAddition,
                         (SELECT        COUNT(*) AS Expr1
                           FROM            dbo.Therapists AS T
                           WHERE        (ClientId = C.Id)) AS TotalTherapistCount,
                         (SELECT        COUNT(*) AS Expr1
                           FROM            dbo.Therapists AS T INNER JOIN
                                                     dbo.ApplicationUsers AS A ON T.ClientId = C.Id AND T.ApplicationUserId = A.Id
                           WHERE        (A.IsDeleted = 0) AND (A.IsDisabled = 0)) AS ActiveTherapistCount,
                         (SELECT        MAX(A.CreatedWhen) AS Expr1
                           FROM            dbo.Therapists AS T INNER JOIN
                                                     dbo.ApplicationUsers AS A ON T.ClientId = C.Id AND T.ApplicationUserId = A.Id) AS LastTherapistAddition,
                         (SELECT        MAX(A.LastLoginDate) AS Expr1
                           FROM            dbo.Therapists AS T INNER JOIN
                                                     dbo.ApplicationUsers AS A ON T.ClientId = C.Id AND T.ApplicationUserId = A.Id
                           WHERE        (A.LastLoginDate IS NOT NULL)) AS TherapistLastLoginDate, CAST((CASE WHEN
                         ((SELECT        COUNT(S.[Id])
                             FROM            [dbo].[ClientSubscriptions] AS S
                             WHERE        ((S.[ClientId] = C.[Id]) AND (S.[IsDeleted] = 0) AND ((S.[SubscriptionEnd] IS NULL) OR
                                                      (S.[SubscriptionEnd] > GETDATE())))) > 0) THEN 1 ELSE 0 END) AS BIT) AS HasActiveSubscription,
                         (SELECT        MAX(SubscriptionEnd) AS Expr1
                           FROM            dbo.ClientSubscriptions AS S
                           WHERE        (ClientId = C.Id) AND (IsDeleted = 0) AND (SubscriptionEnd IS NULL OR
                                                     SubscriptionEnd > GETDATE())) AS LastValidSubscriptionEnd, CAST((CASE WHEN
                         ((SELECT        COUNT(S.[Id])
                             FROM            [dbo].[ClientSubscriptions] AS S
                             WHERE        ((S.[ClientId] = C.[Id]) AND (S.[IsDeleted] = 0) AND ((S.[SubscriptionEnd] IS NULL) OR
                                                      (S.[SubscriptionEnd] > GETDATE())) AND (S.[Id] <>
                                                          (SELECT        MIN(S2.[Id])
                                                            FROM            [dbo].[ClientSubscriptions] AS S2
                                                            WHERE        ((S2.[ClientId] = C.[Id]) AND (S2.[IsDeleted] = 0)))))) > 0) THEN 1 ELSE 0 END) AS BIT) AS IsPayingCustomer, COALESCE
                         ((SELECT        MAX(MonthlyPrice) AS Expr1
                             FROM            dbo.ClientSubscriptions AS S
                             WHERE        (ClientId = C.Id) AND (IsDeleted = 0) AND (SubscriptionEnd IS NULL OR
                                                      SubscriptionEnd > GETDATE()) AND (MonthlyPrice > 0)), 0.00) AS ActiveSubscriptionMonthlyPrice, MAX(ClientStatus) AS Status, MAX(Phone1) AS Phone, MAX(Phone2) AS Phone2,
                         (SELECT        Code
                           FROM            dbo.DiscountCoupons AS DC
                           WHERE        (Code =
                                                         (SELECT        TOP (1) DiscountCouponCode
                                                           FROM            dbo.ClientPayments AS CP
                                                           WHERE        (ClientId = C.Id)
                                                           ORDER BY Id))) AS DiscountCouponCode,
                         (SELECT        IssuedTo
                           FROM            dbo.DiscountCoupons AS DC
                           WHERE        (Code =
                                                         (SELECT        TOP (1) DiscountCouponCode
                                                           FROM            dbo.ClientPayments AS CP
                                                           WHERE        (ClientId = C.Id)
                                                           ORDER BY Id))) AS DiscountCouponIssuedTo,
                         (SELECT        ClientDiscount
                           FROM            dbo.DiscountCoupons AS DC
                           WHERE        (Code =
                                                         (SELECT        TOP (1) DiscountCouponCode
                                                           FROM            dbo.ClientPayments AS CP
                                                           WHERE        (ClientId = C.Id)
                                                           ORDER BY Id))) AS DiscountCouponClientDiscount, COALESCE
                         ((SELECT        COUNT(Id) AS Expr1
                             FROM            dbo.ClientFiles AS F
                             WHERE        (ClientId = C.Id)), 0) AS TotalFilesCount, COALESCE
                         ((SELECT        SUM(FileSize) AS Expr1
                             FROM            dbo.ClientFiles AS F
                             WHERE        (ClientId = C.Id)), 0) / 1048576.0 AS TotalFilesSize, CAST(MAX(CASE WHEN C.CrmEnded = 1 THEN 1 ELSE 0 END) AS BIT) AS CrmEnded, MAX(CrmStatus) AS CrmStatus, MAX(CrmUnuseReason) 
                     AS CrmUnuseReason,
                         (SELECT        COUNT(1) AS Expr1
                           FROM            dbo.Tipulog_Crm_Calls_new AS CC
                           WHERE        (Cust_id = C.Id)) AS CrmCallCount
FROM            dbo.Clients AS C
WHERE        (IsDeleted = 0)
GROUP BY Id

2 个答案:

答案 0 :(得分:0)

这是一个很不完整的答案,但是您询问如何一次而不是多次在多个子查询中引用一个表。

这是一个示例,您将如何替换所有这些子查询到“患者与治疗”表以及“城市”表中。您真的需要了解联接。

FROM dbo.Clients AS C
join dbo.Cities on Cities.ID=c.CityID
left join (
    SELECT ClientId,
        COUNT(*) AS TotalPatientCount,
        sum(case when IsDeleted = 0 AND IsDisabled = 0 then 1 else 0 end) AS ActivePatientCount,
        MAX(CreatedWhen) AS LastPatientAddition
    FROM  dbo.Patients
    GROUP BY ClientId
    ) Patients on Patients.ClientId = C.Id
left join (
    SELECT ClientId,
        COUNT(*) AS TotalTreatmentCount,
        MAX(CreatedWhen) AS LastTreatmentAddition
    FROM dbo.Treatments
    GROUP BY ClientId
    ) Treatments on Treatments.ClientID = C.Id

然后,您的列列表将替换患者和城市的子查询,如下所示:

Cities.Name AS City,
Patients.TotalPatientCount,
Patients.ActivePatientCount,
Patients.LastPatientAddition,
Treatments.TotalTreatmentCount,
Treatments.LastTreatmentAddition,

那至少应该给你一个主意。

答案 1 :(得分:0)

我将添加第二个答案,即完整的sql。当然,这没有经过测试,因为我们无法访问您的数据,但是我认为您应该可以自己调试它。这段代码中有许多指针应向您展示如何操作。

最基本的是取出所有相关查询并将它们作为子查询。这样做的唯一原因是您使用的所有最大/最小-我视这些数据为依据,认为它们不是必需的,那么您应该将它们取出并直接连接到表中。所有子查询都是左联接-如果可以的话,再次使它们成为普通联接。

还按ID排除了外部组,因为99%的人都不需要这样做,前100%的人也是如此。

SELECT  BusinessTitle, ClientName, ClientType AS Type, CreatedWhen, 
        CASE WHEN C.[CreatedBy] IS NULL THEN 'Client' ELSE 'Admin' END) AS CreatedBy, 
        CAST(CASE WHEN C.IsDisabled = 1 THEN 1 ELSE 0 END AS BIT) AS IsDisabled, 
        ReferenceSource, OtherReferenceSource, Address,
        ApplicationByName.FullName AS ClientAdmin,
        ApplicationByName.Email AS Email,
        Cities.Name AS City,
        Patients.TotalPatientCount,
        Patients.ActivePatientCount,
        Patients.LastPatientAddition,
        Treatments.TotalTreatmentCount,
        Treatments.LastTreatmentAddition,
        Therapists.TotalTherapistCount,
        Therapists.ActiveTherapistCount,
        Therapists.LastTherapistAddition,
        Therapists.TherapistLastLoginDate
        CAST(CASE WHEN Subscriptions.SubscriptionCount>0 then 1 else 0 end as BIT) as HasActiveSubscription,
        Subscriptions.LastValidSubscriptionEnd
        CAST(Subscriptions.IsPayingCustomer AS BIT) AS IsPayingCustomer, 
        COALESCE(ActiveSubscriptionMonthlyPrice,0) as ActiveSubscriptionMonthlyPrice
        ClientStatus AS Status, Phone1 AS Phone, Phone2 AS Phone2,
        ClientPayments.DiscountCouponCode,
        DiscountCoupons.IssuedTo AS DiscountCouponIssuedTo,
        DiscountCoupons.ClientDiscount AS DiscountCouponClientDiscount, 
        COALESCE(ClientFiles.TotalFilesCount,0) AS TotalFilesCount, 
        COALESCE(ClientFiles.TotalFilesSize,0) AS TotalFilesSize, 
        CAST((CASE WHEN C.CrmEnded = 1 THEN 1 ELSE 0 END) AS BIT) AS CrmEnded, 
        CrmStatus, CrmUnuseReason,
        Crm_Calls.CrmCallCount
FROM dbo.Clients AS C
left join (
    select A.UserName,
        max(T.FirstName + ' ' + T.LastName) as FullName,
        max(A.Email) as Email
    from dbo.ApplicationUsers A
    join dbo.Therapists T on T.ApplicationUserId=A.Id
    group by A.Username
    ) ApplicationByName on ApplicationByName.UserName=C.ClientName
join dbo.Cities on Cities.ID=c.CityID
left join (
    SELECT ClientId,
        COUNT(*) AS TotalPatientCount,
        sum(case when IsDeleted = 0 AND IsDisabled = 0 then 1 else 0 end) AS ActivePatientCount,
        MAX(CreatedWhen) AS LastPatientAddition
    FROM  dbo.Patients
    GROUP BY ClientId
    ) Patients on Patients.ClientId = C.Id
left join (
    SELECT ClientId,
        COUNT(*) AS TotalTreatmentCount,
        MAX(CreatedWhen) AS LastTreatmentAddition
    FROM dbo.Treatments
    GROUP BY ClientId
    ) Treatments on Treatments.ClientID = C.Id
left join (
    select T.ClientId, 
        count(distinct T.Id) as TotalTherapistCount,
        sum(case when A.IsDeleted = 0 AND A.IsDisabled = 0 then 1 else 0 end) as ActiveTherapistCount,
        max(A.CreatedWhen) as LastTherapistAddition,
        max(A.LastLoginDate) as TherapistLastLoginDate
    from Therapists T
    left join dbo.ApplicationUsers A on A.Id=T.ApplicationUserId 
    group by T.ClientId
    ) Therapists on Therapists.ClientID = C.Id
left join (
    SELECT S.ClientId,
        count(*) as SubscriptionCount,
        MAX(SubscriptionEnd) as LastValidSubscriptionEnd,
        MAX(case when MinSub.Id!=S.ID then 1 else 0 end as IsPayingCustomer,
        max(case when MonthlyPrice>0 then 0 end) as ActiveSubscriptionMonthlyPrice
    FROM dbo.ClientSubscriptions S
    join (
        select ClientId, min(Id) as Id 
        from dbo.ClientSubscriptions 
        where IsDeleted=0 
        group by ClientId
        ) MinSub on MinSub.ClientId=ClientSubscriptions.ClientId
    where IsDeleted=0 and (SubscriptionEnd is null or SubscriptionEnd>getdate())
    group by ClientId
    ) Subscriptions on Subscriptions.ClientId=C.Id
left join (
    select ClientId, 
        DiscountCouponCode,
        row_number() over(partition by ClientId, order by Id) rn
    from  dbo.ClientPayments
    ) ClientPayments on ClientPayments.ClientId=C.ID and rn=1
left join dbo.DiscountCoupons on DiscountCoupons.Code=ClientPayments.DiscountCouponCode
left join (
    select ClientId,
        count(*) as TotalFilesCount,
        sum(FileSize)/1048576.0 as TotalFilesSize
    from dbo.ClientFiles
    group by ClientId
    ) ClientFiles on ClientFiles.ClientId=Client.Id
left join (
    SELECT Cust_id, COUNT(1) AS CrmCallCount
    FROM dbo.Tipulog_Crm_Calls_new 
    group by Cust_id
    ) Crm_Calls on Crm_Calls.Cust_id=C.Id
WHERE C.IsDeleted = 0