我们有许多机器以零星的间隔将数据记录到数据库中。对于每条记录,我想获得此录制和之前录制之间的时间段。
我可以使用ROW_NUMBER执行此操作,如下所示:
WITH TempTable AS (
SELECT *, ROW_NUMBER() OVER (PARTITION BY Machine_ID ORDER BY Date_Time) AS Ordering
FROM dbo.DataTable
)
SELECT [Current].*, Previous.Date_Time AS PreviousDateTime
FROM TempTable AS [Current]
INNER JOIN TempTable AS Previous
ON [Current].Machine_ID = Previous.Machine_ID
AND Previous.Ordering = [Current].Ordering + 1
问题是,它真的慢(在一个有大约10k条目的表上几分钟) - 我尝试在Machine_ID和Date_Time上创建单独的指示,以及一个连接索引,但没有任何帮助
无论如何都要重写这个查询以加快速度吗?
答案 0 :(得分:7)
给定的ROW_NUMBER()分区和顺序要求(Machine_ID, Date_Time)
上的索引在一次传递中满足:
CREATE INDEX idxMachineIDDateTime ON DataTable (Machine_ID, Date_Time);
Machine_ID和Date_Time上的单独索引几乎没有帮助。
答案 1 :(得分:6)
与此版本相比如何?:
SELECT x.*
,(SELECT MAX(Date_Time)
FROM dbo.DataTable
WHERE Machine_ID = x.Machine_ID
AND Date_Time < x.Date_Time
) AS PreviousDateTime
FROM dbo.DataTable AS x
或者这个版本?:
SELECT x.*
,triang_join.PreviousDateTime
FROM dbo.DataTable AS x
INNER JOIN (
SELECT l.Machine_ID, l.Date_Time, MAX(r.Date_Time) AS PreviousDateTime
FROM dbo.DataTable AS l
LEFT JOIN dbo.DataTable AS r
ON l.Machine_ID = r.Machine_ID
AND l.Date_Time > r.Date_Time
GROUP BY l.Machine_ID, l.Date_Time
) AS triang_join
ON triang_join.Machine_ID = x.Machine_ID
AND triang_join.Date_Time = x.Date_Time
对于Machine_ID,Date_Time的索引,两者都会表现最佳,并且对于正确的结果,我假设这是唯一的。
你没有提到隐藏在*中的东西,有时候意味着很多,因为Machine_ID,Date_Time索引通常不会覆盖,如果你有很多列,或者他们有很多数据,。 ..
答案 2 :(得分:4)
如果dbo.DataTable中的行数很大,那么由于CTE自身加入自身,您可能会遇到问题。有一篇博文详细解释了这个问题here
在这种情况下偶尔我会创建一个临时表来插入CTE查询的结果,然后对该临时表进行连接(尽管这通常适用于对temp的大量连接的情况表是必需的 - 在单个连接的情况下,性能差异将不太明显)
答案 3 :(得分:2)
我在SQL Server 2005中使用CTE时遇到了一些奇怪的性能问题。在许多情况下,用真实临时表替换CTE解决了这个问题。
在使用CTE进行任何进一步操作之前,我会尝试这个。
我从未找到任何有关我见过的性能问题的解释,并且真的没有时间深入研究根本原因。但是我总是怀疑引擎无法像优化临时表那样优化CTE(如果需要更多优化,可以对其进行索引)。
<强>更新强>
在您评论这是一个视图之后,我首先会使用临时表测试查询,看看它是否表现更好。
如果确实如此,并且使用存储过程不是一个选项,您可以考虑将当前CTE转换为索引/物化视图。在走这条路之前,你会想要阅读这个主题,因为这是一个好主意取决于很多因素,其中最重要的是数据的更新频率。
答案 4 :(得分:0)
如果您使用触发器存储最后一个时间戳,每次减去什么来获得差异怎么办?
答案 5 :(得分:0)
如果您经常需要这些数据,而不是每次提取数据时计算它,为什么不添加列并在添加行时计算/填充它?
(Remus的复合索引将使查询更快;仅运行一次应使其更快。)