我的问题最好作为对Limit result set in sql window function的评论,但我没有必要的声誉来发表评论。
给出一个移动的车辆位置表,对于每个车辆,我希望找到最近记录的位置(以及当时有关该车辆的其他数据)。根据另一个问题的答案,我可以运行以下查询:
表定义:
CREATE TABLE VehiclePositions
(
Id BIGINT NOT NULL,
VehicleID NVARCHAR(12) NULL,
Timestamp DATETIME NULL,
PositionX FLOAT NULL,
PositionY FLOAT NULL,
PositionZ SMALLINT NULL,
Speed SMALLINT NULL,
Heading SMALLINT NULL
)
查询:
select *
from
(select
*,
row_number() over (partition by VehicleID order by Timestamp desc) as ranking
from VehiclePositions) as x
where
ranking = 1
现在,问题在于这会进行全表扫描。我认为通过创建适当的索引,可以避免这种情况:
CREATE INDEX idx_VehicPosition ON VehiclePositions(VehicleID, Timestamp);
但是,SQL Server将愉快地忽略查询中的该索引,并仍然执行稳定的扫描。
注意:我可以让SQL Server使用索引,但是代码相当难看:
DECLARE @ids TABLE (id NVARCHAR(12) UNIQUE)
INSERT INTO @ids
SELECT DISTINCT VehicleID
FROM VehiclePositions
SELECT ep.*
FROM VehiclePositions vp
WHERE Timestamp = (SELECT Max(TimeStamp) FROM VehiclePositions vp2
WHERE vp2.VehicleID = vp.VehicleID)
AND VehicleID IN (SELECT DISTINCT id FROM @ids)
(VehicleID IN...
是因为SQL Server似乎没有实现查找跳过优化。它仍然提出了一个非常不理想的查询计划,该计划两次访问索引,但至少没有这样做在线性时间内执行。
有没有一种方法可以使SQL Server智能地运行窗口函数查询?
我正在使用SQL Server 2014 ...
我们将不胜感激
答案 0 :(得分:0)
我该怎么做:
SELECT *
FROM
(SELECT MAX(Timestamp) as maxtime,
VehicleID
FROM VehiclePositions
GROUP BY VehicleID ) as maxed INNER JOIN
(SELECT Id ,
VehicleID ,
Timestamp ,
PositionX ,
PositionY,
PositionZ,
Speed ,
Heading
FROM VehiclePositions) as vals
ON maxed.maxtime = vals.Timestamp
AND maxed.VehicleID = vals.VehicleID
据我所知,您无法绕过索引扫描两次。
答案 1 :(得分:0)
只要您从表格中选择所有车辆并选择所有列(或至少选择不在索引中的列),我希望表格扫描会不断弹出。
在许多情况下,这实际上是最有效的查询计划。仅当每辆车有很多行(如几页)时,搜索策略才可能更快。
如果每辆车确实有很多行,则可以考虑在Timestamp上对表进行分区...
答案 2 :(得分:0)
您可以使用“ qualify”在Windows函数中过滤结果,如下所示:
select *
from VehiclePositions
qualify row_number() over (partition by VehicleID order by Timestamp desc) = 1