[英]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.