【发布时间】:2011-11-22 20:11:53
【问题描述】:
这是我发现自己所处的场景。
我有一个相当大的表,我需要从中查询最新记录。以下是查询基本列的创建:
CREATE TABLE [dbo].[ChannelValue](
[ID] [bigint] IDENTITY(1,1) NOT NULL,
[UpdateRecord] [bit] NOT NULL,
[VehicleID] [int] NOT NULL,
[UnitID] [int] NOT NULL,
[RecordInsert] [datetime] NOT NULL,
[TimeStamp] [datetime] NOT NULL
) ON [PRIMARY]
GO
ID 列是主键,VehicleID 和 TimeStamp 上存在非聚集索引
CREATE NONCLUSTERED INDEX [IX_ChannelValue_TimeStamp_VehicleID] ON [dbo].[ChannelValue]
(
[TimeStamp] ASC,
[VehicleID] ASC
)ON [PRIMARY]
GO
我正在优化我的查询的表有超过 2300 万行,只是查询需要操作的大小的十分之一。
我需要返回每个 VehicleID 的最新行。
我一直在 StackOverflow 上查看对这个问题的回答,并且在 Google 上进行了相当多的搜索,在 SQL Server 2005 及更高版本上似乎有 3 或 4 种常用方法。
到目前为止,我发现最快的方法是以下查询:
SELECT cv.*
FROM ChannelValue cv
WHERE cv.TimeStamp = (
SELECT
MAX(TimeStamp)
FROM ChannelValue
WHERE ChannelValue.VehicleID = cv.VehicleID
)
根据表中的当前数据量,执行大约需要 6 秒,这在合理的范围内,但是随着表将在实时环境中包含的数据量,查询开始执行太慢。
查看执行计划,我关心的是 SQL Server 为返回行所做的工作。
我无法发布执行计划图像,因为我的 Reputation 不够高,但索引扫描正在解析表中的每一行,这大大降低了查询速度。
我尝试使用几种不同的方法重写查询,包括使用 SQL 2005 分区方法,如下所示:
WITH cte
AS (
SELECT *,
ROW_NUMBER() OVER(PARTITION BY VehicleID ORDER BY TimeStamp DESC) AS seq
FROM ChannelValue
)
SELECT
VehicleID,
TimeStamp,
Col1
FROM cte
WHERE seq = 1
但该查询的性能甚至差很多。
我尝试过像这样重构查询,但结果速度和查询执行计划几乎相同:
SELECT cv.*
FROM (
SELECT VehicleID
,MAX(TimeStamp) AS [TimeStamp]
FROM ChannelValue
GROUP BY VehicleID
) AS [q]
INNER JOIN ChannelValue cv
ON cv.VehicleID = q.VehicleID
AND cv.TimeStamp = q.TimeStamp
我在表结构方面有一些灵活性(尽管程度有限),因此我可以向数据库中添加索引、索引视图等,甚至是其他表。
如果能提供任何帮助,我将不胜感激。
编辑添加了执行计划图片的链接。
【问题讨论】:
-
问题已投票,您现在应该可以发布您的图片了 :)
-
您能否在 VehicleID 和 TimeStamp 上显示非聚集索引的
create index命令? -
您是否尝试过在 TimeStamp 上添加索引?另请注意,测试时间戳相等性可能会导致问题。
-
我添加了非聚集索引创建脚本。我也玩过索引,但查询执行计划一直遇到同样的问题。
-
如果您总是想要最新的日期,那么也许可以尝试使用
(VehicleID, Timestamp DESC)上的索引,但我认为您无法避免扫描(但至少在这种情况下会订购)。
标签: sql-server performance tsql greatest-n-per-group database-performance