2

使用 SQL2008,我试图找出一个有效的查询来查找日期最接近特定目标日期的行。

有明显低效的解决方案(例如使用ABS 和 DATEDIFF的表扫描),我没有费心去看,因为我的表已经有一个覆盖索引,其中日期是第一列。在准确确定最近的行之前,我可以使用该索引缩小结果范围。

从理论上讲,我应该能够使用单个索引查找来满足查询,然后从该索引中顺序提取 2 行数据。

但到目前为止,我一直无法找到比这个更优化的解决方案:

DECLARE @target DATETIME = '01/02/2011'

SELECT TOP 1 Val, Measured
FROM (
   SELECT TOP 1 Val, Measured 
       FROM tbl 
       WHERE Measured <= @Target 
       ORDER BY Measured desc
   UNION ALL
   SELECT TOP 1 Val, Measured 
       FROM tbl 
       WHERE Measured >= @Target 
       ORDER BY Measured asc
) x
ORDER BY ABS (DATEDIFF (second, Measured, @Target))

这很快(在下面的测试模式中进行 4 次逻辑读取,在我的真实表中进行 9 次逻辑读取),但它仍然是 2 次扫描计数的解决方案。有没有更有效的解决方案,只命中这个索引一次?

还是我现有的解决方案“足够好”,因为第二次索引搜索将拉取第一次搜索访问的缓存页面,这意味着它会非常快,以至于进一步优化(即使可能)将产生最小的实际性能改进?

这是架构和一些示例数据。两者都是从我的实际模式中简化的,尽管生成的查询计划与我更复杂的表相同:

CREATE TABLE tbl
(
    ID int IDENTITY(1,1) PRIMARY KEY CLUSTERED NOT NULL,
    Measured DATETIME NOT NULL,
    Val int NOT NULL
);
CREATE NONCLUSTERED INDEX IX_tbl ON tbl (Measured) INCLUDE (Val)
INSERT tbl VALUES ('2011-01-01 12:34',6);
INSERT tbl VALUES ('2011-01-01 23:34',6);
INSERT tbl VALUES ('2011-01-03 09:03',12);
INSERT tbl VALUES ('2011-02-01 09:24',18);
INSERT tbl VALUES ('2011-02-08 07:12',7);
INSERT tbl VALUES ('2011-03-01 12:34',6);
INSERT tbl VALUES ('2011-04-03 09:03',12);
INSERT tbl VALUES ('2011-05-01 09:24',18);
INSERT tbl VALUES ('2011-06-08 07:12',7);
-- insert another few million rows here to compare to my real-world table
4

1 回答 1

1

考虑首先确定您的@target 在表中的哪个位置,然后首先将+1 / -1 的搜索范围限制在一天或一周内。然后在该集合中按日期排序以找到最接近的成本将低于将 TOP 1/ORDER BY 应用于每一侧的整个集合。

于 2011-07-19T16:38:11.310 回答