SQL查询优化 - 在表上只进行一次连接

时间:2018-03-14 13:53:08

标签: sql sql-server

我有一个大型SQL查询,我需要选择一些数据。

 SELECT p.Id, p.UserId, u.Name AS CreatedBy, p.JournalId, p.Title, pt.Name AS PublicationType, p.CreatedDate, p.MagazineTitle, /*ps.StatusId,*/ p.Authors, pb.Name AS Publisher,  p.Draft,jns.Name AS JournalTitle,

 ISNULL(
    ISNULL(                             
        (SELECT StatusId FROM [PublicationsStatus] WHERE StatusDate=
        (SELECT MAX(StatusDate) FROM [PublicationsStatus] AS ps WHERE ps.PublicationId = p.Id )),--AND ps.UserId = @UserId ORDER BY StatusDate DESC),
        (SELECT TOP(1) ActionId + 6 FROM [PublicationsQuoteSaleLines] AS pqsl WHERE pqsl.PublicationId = p.Id ORDER BY pqsl.Id)
        ),
        1
    )AS StatusId            

    ,ISNULL(
        (SELECT MAX(StatusDate) FROM [PublicationsStatus] AS ps WHERE ps.PublicationId = p.Id ),--AND ps.UserId = @UserId),
        p.CreatedDate
        ) AS StatusDate 
    ,ISNULL(
    (cast((SELECT MAX(StatusDate) FROM [PublicationsStatus] AS ps WHERE ps.PublicationId = p.Id) as date) ),--AND ps.UserId = @UserId),
    p.CreatedDate
    ) AS StDate                 
,CASE 
WHEN ISNULL(
ISNULL(                             
(SELECT StatusId FROM [PublicationsStatus] WHERE StatusDate=
(SELECT MAX(StatusDate) FROM [PublicationsStatus] AS ps WHERE ps.PublicationId = p.Id )),--AND ps.UserId = @UserId ORDER BY StatusDate DESC),
(SELECT TOP(1) ActionId + 6 FROM [PublicationsQuoteSaleLines] AS pqsl WHERE pqsl.PublicationId = p.Id ORDER BY pqsl.Id)
),
1   ) IN (1, 7, 8) THEN 0                       
ELSE 1 END AS OrderCriteria 
,(SELECT COUNT(*) FROM SentEmails AS se WHERE se.PublicationId = p.Id AND se.EmailType = 1 AND se.UserId = @UserId) AS NumberOfAlerts
                ,(SELECT COUNT(*) FROM SentEmails AS se WHERE se.PublicationId = p.Id AND se.EmailType = 3 AND se.UserId = @UserId) AS NumberOfReminders        
            FROM Publications AS p 
            LEFT JOIN PublicationTypes AS pt ON p.PublicationTypeId = pt.Id 
            LEFT JOIN Publishers AS pb ON p.PublisherId = pb.Id 
            LEFT JOIN Journals As jns ON p.JournalId = jns.Id
            LEFT JOIN Users AS u ON u.Id = p.UserId

问题是查询很慢。如你所见,我在OrderCriteria和StatusId上有同样的东西。 StatusDate我来自同一张桌子。 我认为我可以解决性能只能制作一个\

 LEFT JOIN

类似的东西:

  LEFT JOIN (
                SELECT 
                    PublicationId, 
                    StatusId AS StatusId,
                    StatusDate  AS StatusDate                   
                FROM [PublicationsStatus] WHERE StatusDate=
                (
                   SELECT MAX(StatusDate) FROM PublicationsStatus
                )
            ) AS ps ON ps.PublicationId = p.Id

但是我没有这样得到相同的结果。 你能给些建议么?

1 个答案:

答案 0 :(得分:0)

我尝试使用一些CTE简化您的查询,以避免多次执行相同的子查询。你可以尝试一下,看看它是否仍然很慢。

;WITH MaxStatusDateByPublication AS
(
    SELECT
        PublicationId = ps.PublicationId,
        MaxStatusDate = MAX(ps.StatusDate)
    FROM
        [PublicationsStatus] AS ps
    GROUP BY
        PS.PublicationId
),
StatusForMaxDateByPublication AS
(
    SELECT
        StatusId = PS.StatusId,
        M.PublicationId,
        M.MaxStatusDate
    FROM
        MaxStatusDateByPublication AS M
        INNER JOIN [PublicationsStatus] AS PS ON 
            M.PublicationId = PS.PublicationId AND
            M.MaxStatusDate = PS.StatusDate
),
SentEmailsByPublicationAndType AS
(
    SELECT
        S.PublicationID,
        S.EmailType,
        AmountSentEmails = COUNT(1)
    FROM
        SentEmails AS S
    WHERE
        S.EmailType IN (1, 3) AND
        S.UserID = @UserId
    GROUP BY
        S.PublicationID,
        S.EmailType
)
SELECT
    p.Id,
    p.UserId, 
    u.Name AS CreatedBy, 
    p.JournalId, 
    p.Title, 
    pt.Name AS PublicationType, 
    p.CreatedDate, 
    p.MagazineTitle, 
    p.Authors, 
    pb.Name AS Publisher,  
    p.Draft,
    jns.Name AS JournalTitle,
    COALESCE(MS.StatusId, SL.StatusId, 1) AS StatusId,
    ISNULL(MS.MaxStatusDate, P.CreatedDate) AS StatusDate,
    ISNULL(CONVERT(DATE, MS.MaxStatusDate), P.CreatedDate) AS StDate,
    CASE
        WHEN COALESCE(MS.StatusId, SL.StatusId, 1) IN (1, 7, 8) THEN 0
        ELSE 1 
    END AS OrderCriteria,
    ISNULL(TY1.AmountSentEmails, 0) AS NumberOfAlerts,
    ISNULL(TY3.AmountSentEmails, 0) AS NumberOfReminders
FROM
    Publications AS p 
    LEFT JOIN PublicationTypes AS pt ON p.PublicationTypeId = pt.Id 
    LEFT JOIN Publishers AS pb ON p.PublisherId = pb.Id 
    LEFT JOIN Journals As jns ON p.JournalId = jns.Id
    LEFT JOIN Users AS u ON u.Id = p.UserId
    LEFT JOIN StatusForMaxDateByPublication AS MS ON P.Id = MS.PublicationId
    LEFT JOIN SentEmailsByPublicationAndType AS TY1 ON 
        P.Id = TE.PublicationID AND
        TY1.EmailType = 1
    LEFT JOIN SentEmailsByPublicationAndType AS TY3 ON 
        P.Id = TE.PublicationID AND
        TY1.EmailType = 3
    OUTER APPLY (
        SELECT TOP 1
            StatusId = ActionId + 6
        FROM
            [PublicationsQuoteSaleLines] AS pqsl
        WHERE
            pqsl.PublicationId = P.Id
        ORDER BY 
            pqsl.Id ASC) AS SL

尽量避免多次写入相同的表达式(特别是如果它在列中放入子查询!)。使用一些CTE和正确识别将有助于提高可读性。

这是一个复杂的查询,涉及多个表。如果您的查询运行缓慢,可能有许多不同的原因。尝试自己执行每个子查询以检查它们是否很慢,然后尝试将它们1加1加入。如果连接列的索引不存在,那么可能 可以提高性能。发布完整的查询执行计划可能会有所帮助。