2011-05-20 17 views
1

我这个叫从第三方应用程序StateChanges(190万行)大表包含此数据:的SQL Server:获取最后一个记录一组给定的组件的某个特定日期之前发生

[ComponentID] : integer : Id of what changed 
[NewStatus] : integer : How it changed (0: OK, 1: Error, 2:Warning) 
[ConsoleTimeStamp] : timestamp, index : When it changed. 

我需要在两个日期之间显示一堆组件状态的各种更改。这是相当微不足道的。然而,我显示我的数据是这样的:

[OldStatus] --> [New Status] | [ConsoleTimeStamp] 

我的问题是,为了获得给定的组件的“初始”状态,我需要让行立即初始日期前所有组件。没有任何我们可以确定的范围,在2003年和现在之间可能没有变化。

单个组件,我能得到这个查询足够快的工作:

SELECT TOP 1 [NewStatus], [ConsoleTimeStamp] FROM [StateChanges] 
WHERE [ComponentID] = ? AND [ConsoleTimeStamp] < ? 
ORDER BY [ConsoleTimeStamp] DESC 

现在,有没有办法让所有的“以前的状态”为我所有的组件(ID被在一个数组中)以有效的方式?我已经试过:

SELECT ComponentId, NewStatus, MAX(ConsoleTimeStamp) As LastDate FROM StateChanges 
WHERE ComponentId IN ({0}) AND ConsoleTimeStamp <= ? 
GROUP BY ComponentId,NewStatus 
ORDER BY ComponentId ASC, LastDate ASC 

这个解决方案恰好是真正的慢(和给予额外的结果我并不需要)相比,取整组两个日期之间变化的其他查询。

谢谢。

+0

得爱你的gravatar :-) – 2011-05-20 18:16:23

回答

1

我不完全确定我完全理解你的问题 - 但一种方法是使用CTE(公用表表达式)如果你在SQL Server 2005及更新的版本(你在这方面不够具体)。

使用此CTE,您可以按照某些条件(即ComponentId)对数据进行分区,并且SQL Server编号从1开始,每个分区按照其他条件排序,即可能为ConsoleTimeStamp

因此,尝试这样的事:

;WITH PartitionedComponents AS 
(
    SELECT 
     ComponentId, NewStatus, ConsoleTimeStamp, 
     ROW_NUMBER() OVER(PARTITION BY ComponentId ORDER BY ConsoleTimeStamp DESC) AS 'RowNum' 
    FROM 
     dbo.StateChanges 
    WHERE 
     ComponentId IN (.....) 
     AND ConsoleTimeStamp <= (threshold) 
) 
SELECT 
    ComponentId, NewStatus, ConsoleTimeStamp, RowNum 
FROM 
    PartitionedComponents 
WHERE 
    RowNum <= 2 

在这里,我对每个“分区”只选择最后两个条目(即每个ComponentId) - 由ConsoleTimeStamp降序排序方式。

这是否接近你要找的?

+1

我正在使用SQL Server 2008,并且这种方法工作完美!它的运行时间缩短了一半(1000ms而不是2200ms),我可以通过删除没有任何日期1和日期2条目的ComponentID来减少时间。我只希望制作第三方软件的人添加一个“OldStatus”列 - 使我能够在快速(5ms)查询中检索信息。 – 2011-05-20 19:41:34

相关问题