Мне нужно выбрать верхний ряд для каждой категории из известного набора (несколько похожий на 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 строки. Для первого запроса три раза выбирается одна строка.
Есть ли способ эффективно выполнить запрос без большого количества профсоюзов?
+1 для включения образца кода –