У меня есть таблица, которая содержит много данных, где нам особенно важно поле date
. Причиной этого является то, что объем данных увеличился примерно в 30 раз, и старые способы скоро рухнут. Запрос, который, я надеюсь, вы можете помочь мне оптимизировать, должен:
- взять список дат (генерируется табличной функцией на основе cte)
- получить одну запись для каждой из этих дат
- на основе некоторого определения «ближайшего» * 1009 *
Например, текущая таблица содержит данные с интервалами в 5 секунд (+/- немного). Мне нужно отобрать эту таблицу и получить запись, которая находится ближе всего к 30-секундному интервалу.
То, что у меня сейчас есть, работает просто отлично. Мне просто любопытно, если есть способ оптимизировать это больше. Если бы я мог сделать это в Linq To SQL, это тоже было бы здорово. Меня даже интересуют предложения по индексам, учитывая количество значений даты (~ 2 млн. Мин строк).
declare @st datetime ; set @st = '2012-01-31 05:05:00';
declare @end datetime ; set @end = '2012-01-31 05:10:00';
select distinct
log.* -- id,
from
dbo.fn_GenerateDateSteps(@st, @end, 30) as d
inner join lotsOfLogData log on l.Id = (
select top 1 e.[Id]
from
lotsOfLogData as log -- contains data in 5 second intervals
where
log.stationId = 1000
-- search for dates in a certain range
AND utcTime between DateAdd(s, -10, dt) AND DateAdd(s, 5, dt)
order by
-- get the 'closest'. this can change a little, but will always
-- be based on a difference between the date
abs(datediff(s, dt, UtcTime))
)
-- updated the query to be correct. stadionId should be inside the subquery
Структура таблицы lotsOfLogData приведена ниже. Идентификаторов станций относительно немного (может быть, 50), но много записей для каждой. Мы знаем идентификатор станции, когда запрашиваем.
create table ##lotsOfLogData (
Id bigint identity(1,1) not null
, StationId int not null
, UtcTime datetime not null
-- 20 other fields, used for other calculations
)
fn_GenerateDateSteps возвращает такой набор данных для заданных параметров:
[DT]
2012-01-31 05:05:00.000
2012-01-31 05:05:30.000
2012-01-31 05:06:00.000
2012-01-31 05:06:30.000 (and so on, every 30 seconds)
Я также сделал это с временной таблицей, но это оказалось немного дороже.
declare @dates table ( dt datetime, ClosestId bigint);
insert into @dates (dt) select dt from dbo.fn_GenerateDateSteps(@st, @end, 30)
update @dates set closestId = ( -- same subquery as above )
select * from lotsOfLogData inner join @dates on Id = ClosestId
Редактировать: Исправлено
Теперь 200K + строк для работы. Я попробовал оба способа, и перекрестное применение с соответствующим индексом (id / time + includes (... все столбцы ...) работало просто отлично. Однако я закончил запросом, который начал, используя более простой (и существующий) индекс на [id + время]. Более понятный вопрос - почему я остановился на этом. Может быть, есть еще лучший способ сделать это, но я не вижу его: D
-- subtree cost (crossapply) : .0808
-- subtree cost (id based) : .0797
-- see above query for what i ended up with