问题
我最近了解了CTE以及如何使用它们来获得性能,但我认为在这种情况下我过度使用它们。以下查询大约需要1分钟,只有1000次考试,我相信它可以更快地完成。请建议可以指向正确方向的优化或术语?
上下文
要理解查询,您需要有一些上下文,所以在这里。在数据库中,我们有考试,这将在对象上执行(E.G.如果笔可以写,则需要检查笔)。在考试开始前,必须确认考试,因此确认日期。当然,我们也会在创建考试时保存( createdate )。当考试准备就绪时(准备日期),它需要得到一个结果。结果可以被批准(已批准)或被拒绝(被拒绝)。此查询的含义是创建图表,显示每天的5个检查条件。
每天所需的计数:
实际查询
DECLARE @ProjectID [bigint] = 3
DECLARE @LocationID [bigint] = 2
DECLARE @PersonID [bigint] = 1058
DECLARE @StartDate [datetime] = '2012-01-01'
DECLARE @EndDate [datetime]= '2014-12-31'
;WITH ExaminationCTE(acknowledgedate, readydate, createdate, isrejected, isapproved)
AS
(
SELECT [acknowledgedate], [readydate], createdate, [isrejected], [isapproved] FROM [dbo].[Examination]
LEFT JOIN [dbo].[Object] [o] ON [dbo].[Examination].[fk_objectid] = [o].[pk_objectid]
LEFT JOIN [dbo].[ExaminationResults] [er] ON [dbo].[Examination].[fk_examinationid] = [er].[pk_examinationid]
WHERE [fk_projectid] = @ProjectID
AND [fk_locationid] = @LocationID
AND [fk_personid] = @PersonID
),
dates(Date) AS
(
--Get all the dates between the selected range
SELECT @StartDate as Date
UNION ALL
SELECT DATEADD(d,1,[Date])
FROM dates
WHERE DATE < @EndDate
)
-- Select all the counts from the examination CTE
SELECT d.Date,
(SELECT COUNT(*) FROM [ExaminationCTE] WHERE [createdate] <= [d].[Date]) AS 'examinations_created_count',
(SELECT COUNT(*) FROM [ExaminationCTE] WHERE [acknowledgedate] <= [d].[Date]) AS 'examinations_acknowledged_count',
(SELECT COUNT(*) FROM [ExaminationCTE] WHERE [readydate] <= [d].[Date]) AS 'examinations_ready_count',
(SELECT COUNT(*) FROM [ExaminationCTE] WHERE [readydate] <= [d].[Date] AND [isapproved] = 1) AS 'examinations_ready_and_approved_count',
(SELECT COUNT(*) FROM [ExaminationCTE] WHERE [readydate] <= [d].[Date] AND [isrejected] = 1) AS 'examinations_ready_and_rejected_count'
FROM dates d
OPTION (MAXRECURSION 0)
当查询正在运行时,它不符合我的性能规格。我觉得这可以做得更整洁。
更新 由于@GordonLinoff的帮助,我几乎就在那里。但是我需要用最后一个可能的值填充NULL行。
在图像中,您可以看到结果为空箭头,指出值应该是什么,对于第一组NULL我需要从所选开始日期之前的最后一个可用日期获取值。
答案 0 :(得分:1)
是的,你可以提高效率。你正在做一大堆相关的非等值连接,然后计算结果。
采取不同的方法。一种简单的方法是按日期汇总ExaminationCTE
,以总结结果。但是,在SQL Server中,CTE未实现,因此这可能不会改变性能。
另一种方法是使用窗口函数进行计数。以下是第一个字段的示例:
from dates left outer join
(select createdate, max(seqnum) as examinations_created_count
from (select createdate, row_number() over (order by createdate) as seqnum
from ExaminationCTE
) e
group by createdate
) ecc
on dates.date = ecc.createdate
其他人会类似。实际上,您可以将所有变量放在一个子查询中。
逻辑是为每一行添加一个序号,然后取每个日期的最大数量。这是计数。