尽量避免加入大表

时间:2015-02-05 16:12:37

标签: sql sql-server

我正在使用sql-server。我有一个表格如下:

Name    timestamp                var1    
Bill    2015-02-05 10:10:10       x1
Bill    2015-02-05 10:10:11       x2
...
Jim     2015-02-05 10:10:10       y1
Jim     2015-02-05 10:10:11       y2
...
John    2015-02-05 10:10:10       z1
John    2015-02-05 10:10:11       z2

该表非常大,表示100万行,时间戳每秒更新一次。我想选择任何一分钟内var1值改变delta var1的人(即x61-x1或x62-x2等)在5-7之间。这是我加入的代码。

declare @duration int
 set @duration = 60

    SELECT a.name,
          a.var1-b.var1 AS change
 From Table1  a
 inner join Table1 b
   on a.name = b.name
   and a.timestamp = b.timestamp +  @duration
 Where change between 5 and 7

但是,我知道有两个主要问题。

  1. 无法像这样比较时间戳。有什么办法可以解决吗?
  2. 我的桌子太大了。如果每次加入,运行时间太长。有什么想法可以避免吗?

3 个答案:

答案 0 :(得分:2)

假设@duration加入的分钟数应为

....
and a.timestamp = DATEADD(mi,@duration,b.timestamp)
....

答案 1 :(得分:1)

如果您使用的是SQL Server 2012或更高版本,则可以使用LAG() - 窗口函数解决此问题,因为您可以将行的值与前一个值进行比较,如果您正确地对它们进行了排序那是你感兴趣的人。

https://msdn.microsoft.com/en-us/library/hh231256.aspx

应该可以调整" Gaps and Islands"也是这个问题的解决方案。

编辑,发现Itzik Ben-Gan的帖子我记得早些时候读过,这属于"特殊岛屿"类别:

http://sqlmag.com/sql-server-2012/solving-gaps-and-islands-enhanced-window-functions

答案 2 :(得分:1)

请尝试以下

declare @duration int
set @duration = 60

SELECT 
     a.name,
     (SELECT TOP (1) a.var1-b.var1 
      FROM  Table1 b  
      WHERE a.name = b.name
          and a.timestamp = DATEADD(second, @duration , b.timestamp)
          AND  (a.var1-b.var1) between 5 and 7) As Change
FROM
    Table1 AS a

我希望这可能会有所帮助。