SQL Server / T-SQL:查询优化帮助

时间:2016-08-12 18:36:46

标签: sql sql-server optimization query-optimization

我有这个QA逻辑,可以在AuditID中的每个RoomID中查找错误,以查看他们的AuditType是否从未标记为完成,或者他们是否有两个完整的状态。最后,它只挑选AuditDateRoomID个错误,以避免显示同一个RoomID的多个实例,因为每个房间都有很多审核。

问题是AUDIT表非常大并且需要很长时间才能运行。我想知道是否有更快地达到相同的结果。

提前谢谢!

IF object_ID('tempdb..#AUDIT') is not null  drop table #AUDIT
IF object_ID('tempdb..#ROOMS') is not null  drop table #ROOMS
IF object_ID('tempdb..#COMPLETE') is not null  drop table #COMPLETE
IF object_ID('tempdb..#FINALE') is not null  drop table #FINALE

SELECT distinct 
    oc.HotelID, o.RoomID
INTO #ROOMS
FROM  dbo.[rooms] o
LEFT OUTER JOIN dbo.[hotels] oc on o.HotelID = oc.HotelID
WHERE 
    o.[status] = '2' 
    AND o.orderType = '2' 

SELECT 
    t.AuditID, t.RoomID, t.AuditDate, t.AuditType
INTO  
    #AUDIT
FROM 
    [dbo].[AUDIT] t
WHERE
    t.RoomID IN (SELECT RoomID FROM #ROOMS) 


SELECT 
    t1.RoomID, t3.AuditType, t3.AuditDate, t3.AuditID, t1.CompleteStatus
INTO 
    #COMPLETE
FROM
    (SELECT 
         RoomID,
         SUM(CASE WHEN AuditType = 'Complete' THEN 1 ELSE 0 END) AS CompleteStatus
     FROM 
         #AUDIT
     GROUP BY 
         RoomID) t1
INNER JOIN
    #AUDIT t3 ON t1.RoomID = t3.RoomID
WHERE 
    t1.CompleteStatus = 0
    OR t1.CompleteStatus > 1


SELECT 
    o.HotelID, o.RoomID, 
    a.AuditID, a.RoomID, a.AuditDate, a.AuditType, a.CompleteStatus,
    c.ClientNum
INTO
    #FINALE
FROM 
    #ROOMS O
LEFT OUTER JOIN 
    #COMPLETE a on o.RoomID = a.RoomID
LEFT OUTER JOIN 
    [dbo].[clients] c on o.clientNum = c.clientNum


SELECT
    t.*,
    Complete_Error_Status = CASE WHEN t.CompleteStatus = 0 
                                    THEN 'Not Complete'
                                 WHEN t.CompleteStatus > 1 
                                    THEN 'Complete More Than Once' 
                            END
FROM
    #FINALE t
INNER JOIN
    (SELECT 
         RoomID, MAX(AuditDate) AS MaxDate
     FROM
         #FINALE
     GROUP BY 
         RoomID) tm ON t.RoomID = tm.RoomID AND t.AuditDate = tm.MaxDate

2 个答案:

答案 0 :(得分:0)

只是一个想法。简化您的代码和解决方案。您没有有效地过滤数据集较小,因此您继续查询占用大量资源的整个表,并且临时表正在成为那些没有索引(PK,FK,++ ??)的列的完整副本原始表利用。这绝不是一个完美的解决方案,但它是一个如何整合逻辑和减少整体数据集的想法。试一试,看看它是否对你有好处。

请注意,这将返回任何未完成审核或已完成审核的房间的最后审核记录。

;WITH cte AS (
    SELECT
       o.RoomId
       ,o.clientNum
       ,a.AuditId
       ,a.AuditDate
       ,a.AuditType
       ,NumOfAuditsComplete = SUM(CASE WHEN a.AuditType = 'Complete' THEN 1 ELSE 0 END) OVER (PARTITION BY o.RoomId)
       ,RowNum = ROW_NUMBER() OVER (PARTITION BY o.RoomId ORDER BY a.AuditDate DESC)
    FROm
       dbo.Rooms o
       LEFT JOIN dbo.Audit a
       ON o.RoomId = a.RoomId
WHERE
   o.[Status] = 2
   AND o.OrderType = 2
)

SELECT
    oc.HotelId
    ,cte.RoomId
    ,cte.AuditId
    ,cte.AuditDate
    ,cte.AuditType
    ,cte.NumOfAuditsComplete
    ,cte.clientNum
    ,Complete_Error_Status = CASE WHEN cte.NumOfAuditsComplete > 1 THEN 'Complete More Than Once' ELSE 'Not Complete' END
FROM
    cte
    LEFT JOIN dbo.Hotels oc
    ON cte.HotelId = oc.HotelId
    LEFT JOIN dbo.clients c
    ON cte.clientNum = c.clientNum
WHERE
    cte.RowNum = 1
    AND cte.NumOfAuditsComplete != 1

还要注意我改变了你的

WHERE 
    o.[status] = '2' 
    AND o.orderType = '2'

WHERE 
    o.[status] = 2 
    AND o.orderType = 2

是没有单引号的数字。如果数据类型为true,则varchar将它们添加回来,但是当您将数字列作为varchar查询时,它将执行数据转换,并且可能无法利用您在表上构建的索引。

答案 1 :(得分:0)

你可以改进的一个部分就是这一部分。请参阅内联评论。

SELECT 
    t1.RoomID, t3.AuditType, t3.AuditDate, t3.AuditID, t1.CompleteStatus
INTO 
    #COMPLETE
FROM
    (SELECT 
         RoomID,
         COUNT(1) AS CompleteStatus
         -- Use the above along with the WHERE clause below
         -- so that you are aggregating fewer records and
         -- avoiding a CASE statement. Remove this next line.
         --SUM(CASE WHEN AuditType = 'Complete' THEN 1 ELSE 0 END) AS CompleteStatus
     FROM 
         #AUDIT
     WHERE
         AuditType = 'Complete'
     GROUP BY 
         RoomID) t1
INNER JOIN
    #AUDIT t3 ON t1.RoomID = t3.RoomID
WHERE
    t1.CompleteStatus = 0
    OR t1.CompleteStatus > 1