SQL-запрос медленный - как его оптимизировать? - PullRequest
0 голосов
/ 05 июня 2019

Мне бы хотелось, чтобы некоторая помощь оптимизировала этот запрос, чтобы он был быстрее.

Этот запрос создает представление, что последний будет отображаться в таблице на веб-сайте.Этот запрос медленный, и я пытаюсь сделать его быстрее.

Единственное, что я пытался до сих пор, - это уменьшить количество столбцов, извлекаемых для таблицы.

Это запрос:

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 голосов
/ 07 июня 2019

Я добавлю второй ответ, который является полным sql. Это, конечно, не было проверено, поскольку у нас нет доступа к вашим данным, но я думаю, что вы сможете отладить их самостоятельно. В этом коде есть много указателей, которые должны показать вам, как идти.

Основная задача - вынуть все коррелированные запросы и поместить их в качестве подзапросов. Единственная причина сделать это - все используемые вами максимальные / минимальные значения - я бы посмотрел на них так, как если бы они не были необходимы в зависимости от ваших данных, тогда вы должны вынуть их и напрямую присоединиться к таблицам. Все подзапросы - это оставленные объединения - снова сделайте их обычными объединениями, если это возможно, в зависимости от ваших данных.

Также выбрал внешнюю группу по Id, так как 99% уверены, что в этом нет необходимости, как и бит Top 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
0 голосов
/ 06 июня 2019

Это очень частичный ответ, но вы спросили, как ссылаться на таблицу один раз, а не несколько раз в нескольких подзапросах.

Это пример того, как вы должны заменить все эти подзапросы на пациентов иТаблицы процедур, а также стол городов.Вам действительно нужно узнать об объединениях.

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,

Это должно как минимум дать вам представление.

...