简体   繁体   English

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

[英]SQL Server / T-SQL : query optimization assistance

I have this QA logic that looks for errors into every AuditID within a RoomID to see if their AuditType were never marked Complete or if they have two complete statuses. 我有一个看起来错误到每一个这样的QA逻辑AuditID一个内RoomID ,看看他们AuditType从未标注齐全或者如果他们有两个完整的状态。 Finally, it picks only the maximum AuditDate of the RoomID s with errors to avoid showing multiple instances of the same RoomID , since there are many audits per room. 最后,由于每个房间有很多审核,它只选择有错误的RoomID的最大AuditDate以避免显示同一RoomID多个实例。

The issue is that the AUDIT table is very large and takes a long time to run. 问题是AUDIT表非常大,需要很长时间才能运行。 I was wondering if there is anyway to reach the same result faster. 我想知道是否有更快达到相同结果的方法。

Thank you in advance ! 先感谢您 !

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

Just a thought. 只是一个想法。 Streamline your code and your solution. 简化代码和解决方案。 you are not effectively filtering your datasets smaller so you continue to query the entire tables which is taking a lot of your resources and your temp tables are becoming full copies of those columns without the indexes (PK, FK, ++??) on the original table to take advantage of. 您没有有效地过滤较小的数据集,因此您将继续查询占用大量资源的整个表,而您的临时表已成为这些列的完整副本,而没有索引(PK,FK,++ ??)原始表可以利用。 This by no means is a perfect solution but it is an idea of how you can consolidate your logic and reduce your overall data set. 这绝不是一个完美的解决方案,而是一个有关如何合并逻辑并减少总体数据集的想法。 Give it a try and see if it performs better for you. 尝试一下,看看它是否对您更好。

Note this will return the last audit record for any room that has either not had an audit completed or completed more than once. 请注意,这将返回尚未完成审核或多次完成的所有房间的最后审核记录。

;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

Also note I changed your 另请注意,我更改了您的

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

TO

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

to be numeric without the single quotes. 为数字,不带单引号。 If the data type is truely varchar add them back but when you query a numeric column as a varchar it will do data conversion and may not take advantage of indexes that you have built on the table. 如果数据类型的确是varchar,则将它们添加回去,但是当您将数字列查询为varchar时,它将进行数据转换,并且可能不会利用在表上建立的索引。

One section you could improve would be this one. 您可以改进的部分就是这一部分。 See the inline comments. 请参阅内联注释。

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM