2012-02-16 3 views
5

У меня есть таблица, которая содержит много данных, где мы особенно заботимся о поле date. Причиной этого является то, что объем данных только поднялся ~ 30 раз, и старые способы скоро распадятся. Запрос я надеюсь, что вы можете мне помочь оптимизировать потребности в:Попытка оптимизировать запрос, который выбирает «приблизительную ближайшую запись»

  • взять список дат (порожденный табличную функцией на основе КТРА)
  • получить одну запись для каждого из этих дат
    • на основе некоторого определения «ближайший»

например, текущая таблица содержит данные в 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 

Edit: Исправлена ​​

Got 200K + строки для работы с компанией. Я пробовал в обоих направлениях, и крест применим с соответствующим индексом (id/time + includes (..все столбцы ...) работал отлично. Однако я закончил с запросом, который я начал, используя более простой (и существующий) . индекс [ид + время] более широко понятно запрос, почему я остановился на том, что один может быть, есть еще лучший способ сделать это, но я не могу видеть это.: D

-- subtree cost (crossapply) : .0808 
-- subtree cost (id based) : .0797 

-- see above query for what i ended up with 

ответ

1

Вы можете попробовать

  • изменяя inner join к cross apply.
  • Переместить where log.stationid в подзадачу.

SQL Заявление

SELECT DISTINCT log.* -- id, 
FROM dbo.fn_GenerateDateSteps(@st, @end, 30) AS d 
     CROSS APPLY (
      SELECT TOP 1 log.* 
      FROM lotsOfLogData AS log -- contains data in 5 second intervals 
      WHERE -- search for dates in a certain range 
        utcTime between DATEADD(s, -10, d.dt) AND DATEADD(s, 5, d.dt) 
        AND log.stationid = 1000 
      ORDER BY 
        -- get the 'closest'. this can change a little, but will always 
        -- be based on a difference between the date 
        ABS(DATEDIFF(s, d.dt, UtcTime)) 
     ) log 
+0

. Cross apply хочет, чтобы я сделал индекс на stationid/time, который также включает * все * другие данные в таблице. Без индекса он работает точно так же, как и голый запрос, поэтому в этом случае крест не будет работать :) Я даже не знал об этом, так что спасибо! –

+0

О, и у меня была ошибка в этом запросе;) Я * обязательный *, чтобы поставить stationId в подзапрос, потому что иначе я буду соответствовать любому stationId, находящемуся в диапазоне. После этого используется правильный индекс, и все очень быстро (ish) –

+0

@AndrewBacker - Прошел, но спасибо, что сообщили нам об этом. –

1

Просто некоторые мысли ... на самом деле не назовешь это ответом, но он слишком велик для поля комментариев.

Прежде всего, я бы рассмотрел план выполнения запроса, если вы еще этого не сделали.

Более эзотерический: есть ли у вас возможность представлять даты как примитивные значения (например, целое число, представляющее секунды/минуты с четко определенного времени)? Хотя я считаю, что SQL Server хранит даты как числовые значения под капотом, операции над примитивом могут быть немного быстрее, потому что это устранит повторные вызовы DateAdd() и DateDiff().

This (fairly old) article дает примеры того, как SQL Server хранит даты. Возможно, вы можете оставить свои даты как DATETIME, но работать с ними с помощью базовой математики.

Независимо от типа данных, я бы экспериментировал с кластеризованным индексом в столбце даты, так как кажется, что ваши поиски могут извлечь выгоду из физического упорядочения, предоставляемого кластеризованным индексом, особенно если вы ищете в жестких диапазонах. Опять же, план выполнения, вероятно, будет просвещен.

Я также мог видеть схему звезд, которая используется для представления ваших данных, с измерением даты, которое содержит обобщения даты. Затем вы можете выполнить поиск против обобщений. Даже если обобщения не использовались, фактическое количество дат будет уменьшено, потому что все факты с той же датой могут указывать на одну и ту же запись в измерении, поэтому дату нужно будет оценивать только один раз.

Наконец, что делает мастер настройки производительности SQL (я считаю, что это в 2005 году, я знаю, что это в 2008 году) предлагает для вашего запроса? Я бы не рекомендовал слепо реализовывать свои предложения, но я часто нахожу хорошие идеи в том, что он рекомендует.

+0

К сожалению, я не могу делать с форматом данных. Внешняя служба получает данные и записывает их там для нас. Я рассмотрел план выполнения, но он просто огромный =) У меня есть кластерный индекс на идентификаторе станции и std. индекс на дату. У меня просто нет достаточных реалистичных данных, чтобы проверить его еще, и с достаточно небольшим набором это, похоже, не имеет значения, если есть индекс или нет. –

Смежные вопросы