【发布时间】:2010-06-04 14:06:45
【问题描述】:
我需要从已知集合中为每个类别选择一个顶行(有点类似于this question)。问题是,如何让这个查询在大量行上高效。
例如,让我们创建一个表来存储多个位置的温度记录。
CREATE TABLE #t (
placeId int,
ts datetime,
temp int,
PRIMARY KEY (ts, placeId)
)
-- insert some sample data
SET NOCOUNT ON
DECLARE @n int, @ts datetime
SELECT @n = 1000, @ts = '2000-01-01'
WHILE (@n>0) BEGIN
INSERT INTO #t VALUES (@n % 10, @ts, @n % 37)
IF (@n % 10 = 0) SET @ts = DATEADD(hour, 1, @ts)
SET @n = @n - 1
END
现在我需要获取位置 1、2、3 的最新记录。
这种方式很有效,但不能很好地扩展(而且看起来很脏)。
SELECT * FROM (
SELECT TOP 1 placeId, temp
FROM #t
WHERE placeId = 1
ORDER BY ts DESC
) t1
UNION ALL
SELECT * FROM (
SELECT TOP 1 placeId, temp
FROM #t
WHERE placeId = 2
ORDER BY ts DESC
) t2
UNION ALL
SELECT * FROM (
SELECT TOP 1 placeId, temp
FROM #t
WHERE placeId = 3
ORDER BY ts DESC
) t3
以下看起来更好,但工作效率要低得多(根据优化器,30% 对 70%)。
SELECT placeId, ts, temp FROM (
SELECT placeId, ts, temp, ROW_NUMBER() OVER (PARTITION BY placeId ORDER BY ts DESC) rownum
FROM #t
WHERE placeId IN (1, 2, 3)
) t
WHERE rownum = 1
问题是,在后一个查询执行计划中,对 #t 执行聚集索引扫描,检索、排序、编号和过滤 300 行,只剩下 3 行。对于前一个查询,3 次获取一行。
有没有办法在没有大量联合的情况下高效地执行查询?
【问题讨论】:
标签: sql-server tsql sql-server-2008 query-optimization