SQL Server有效地过滤时间不在另一个表的时间附近的行

Mic*_*art 5 sql t-sql sql-server sql-server-2005

我有两个表,我正在寻找一个表中的行,其中时间列接近另一个表的时间列中的任何值.(近定义为一分钟内).

这是一个代码示例:

create table temp1
(
    id int identity primary key,
    value datetime not null 
)
GO

create index ix_temp1 on temp1(value, id);
GO

set nocount on
insert temp1 (value) values (DATEADD(second, rand() * 1000000, '20100101'))
GO 15000
Run Code Online (Sandbox Code Playgroud)

表temp2设置相同:

create table temp2
(
    id int identity primary key,
    value datetime not null 
)
GO

create index ix_temp2 on temp2(value, id);
GO

set nocount on
insert temp2 (value) values (DATEADD(second, rand() * 1000000, '20100101'))
GO 15000
Run Code Online (Sandbox Code Playgroud)

这是我的第一次破解(这是非常低效的)

SELECT t1.id, t1.value
FROM temp1 t1
LEFT JOIN temp2 t2
    ON t1.value between DATEADD(MINUTE, -1, t2.value) and DATEADD(MINUTE, 1, t2.value)
WHERE t2.value is null
Run Code Online (Sandbox Code Playgroud)

我正在寻找更有效地做到这一点的方法.将考虑所有解决方案(新索引,SSIS解决方案,CLR解决方案,临时表,游标等...)

OMG*_*ies 4

当列不可为空时,LEFT JOIN/IS NULL 在 SQL Server 上的效率不如 NOT IN 或 NOT EXISTS -有关详细信息,请参阅此链接

也就是说,这个:

SELECT t1.id,
       t1.value
  FROM temp1 t1
 WHERE NOT EXISTS(SELECT NULL
                    FROM temp2 t2
                   WHERE t2.value BETWEEN DATEADD(MINUTE, -1, t1.value)  
                                      AND DATEADD(MINUTE, 1, t1.value))
Run Code Online (Sandbox Code Playgroud)

...仍然存在一个问题,即函数使用(IE:DATEADD)导致索引无用。当索引位于原始值上时,您正在更改列的数据(暂时,而不将其写回到表中)。

如果你想要精确度,我会失去选择。否则,如果您在将日期时间插入临时表之前更改日期时间,那么您将获得:

  1. 直接比较能力: t1.value = t2.value
  2. 使用索引的能力,假设优化器认为它有用