Результаты sql 2008 по дате поиска (между) - PullRequest
0 голосов
/ 05 июня 2009

Каков наилучший индекс или идеи для улучшения поиска по диапазону дат? (или запрос на изменение)

    begin tran t1
      delete from h1 where histdate between @d1 and @d2 and HistRecordType = 'L'
      insert into h1 
             select * from v_l WHERE HistDate between @d1 and @d2 
     commit tran t1

это намного медленнее, чем исторических данных = @ d1

У меня есть кластерный неуникальный индекс в столбце даты

однако, перфоманс тот же, что и переход к некластеризованному

если @ d1 = @ d2 .. выполнение запроса занимает 8 минут, histdate = @ d1 выполняется за 1 секунду (так что это должно быть эквивалентно верно?)

Ответы [ 5 ]

3 голосов
/ 05 июня 2009

Кластерный индекс - это лучший индекс для запросов.

Делаете ли вы что-нибудь еще в части WHERE, тогда могут быть способы улучшить запрос.

Быстрый почему; кластеризованный индекс будет сортировать строки в таблице (поэтому у вас может быть только один кластеризованный индекс на таблицу). Таким образом, SQL-серверу сначала нужно найти первую возвращаемую строку (@ d1), затем все строки хранятся в порядке и быстро возвращаются. Histdate = @ d1 быстрее, так как все, что нужно сделать, это найти первую строку, ей не нужно продолжать поиск всех других строк до @ d2.

1 голос
/ 05 июня 2009

DateTime хранится как float внутри, поэтому ваш текущий пример должен быть довольно эффективным. Одна потенциальная оптимизация будет иметь другой столбец, такой как DayOffset, который рассчитывается по DATEDIFF (день, 0, histDate) Это будет первый столбец кластерного ключа.

Тогда, если вы удаляете целые дни за раз, вы можете просто удалить на основе DayOffset. Если вы не хотите удалять на полуночных границах, вы можете удалить данные на основе пары DayOffset и диапазона дат.

WHERE DayOffset between DATEDIFF(day, 0, @d1) and DATEDIFF(day, 0, @d2)
  and histdate between @d1 and @d2

Другой возможный вариант - использовать разбиение. Намного эффективнее устаревать данные путем удаления старого раздела, чем удалять строки.

1 голос
/ 05 июня 2009

Некластеризованный индекс для столбца будет иметь ту же производительность, что и кластеризованный ключ, при условии, что некластеризованный индекс содержит все поля (в индексе или в столбцах INCLUDE) для любого оператора SELECT против него (a так называемый «индекс покрытия»).

Единственная причина, по которой кластерный индекс во многих случаях будет быстрее для запросов диапазона - это тот факт, что кластерный индекс IS данные таблицы, поэтому любой столбец, который вам может понадобиться, находится прямо в кластерном индексе. С покрывающим индексом вы достигнете того же результата - если индекс плюс какие-либо столбцы INCLUDE содержат все столбцы, которые должен извлечь ваш оператор SELECT, вы можете удовлетворить запрос, просто взглянув на индекс - нет необходимости переходить от кластеризованный индекс в фактическую таблицу для извлечения большего количества данных («поиск по закладкам», который имеет тенденцию быть медленным для многих поисков).

Для DELETE, я не думаю, что это действительно имеет какое-то значение, если у вас есть индекс для этого столбца, используемый в предложении WHERE (histdate).

Марк

0 голосов
/ 26 июля 2011

Поскольку индексы хранятся в двоичной древовидной структуре (отсортированной, а не хеш), механизм может приравнять диапазон предложения where к диапазону индексов путем поиска в двух местах.

Однако иногда механизм может выбрать сканирование всего индекса, даже если указанный диапазон приводит к извлечению только нескольких записей. План объяснения должен показывать, был ли для запроса выбран поиск индекса или сканирование индекса.

В качестве примера, может быть низкая производительность при запросе диапазона выбора, который возвращает небольшое количество <10 записей из таблицы строк с миллионами с индексом (бывает некластеризованным, но не точкой) в диапазоне значений ( индекс v1 + v2): </p>

select * from 
      tbl t
    where t.v1 = 123
      and t.v2 < 4;

Поскольку поиск по индексу, вероятно, является лучшим выбором для этого случая (малый набор возвращаемых значений), его можно указать с помощью «with (forceseek)».

select * 
  from tbl t with (forceseek)   -- is 6x faster for this case
 where t.v1 = 123
   and t.v2 < 4;

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

0 голосов
/ 05 июня 2009

попробуйте каждый из них с помощью "SET SHOWPLAN_ON ALL"

delete from h1 where  histdate  between CONVERT(datetime,'1/1/2009') and CONVERT(datetime,'5/30/2009')

delete from h1 where  histdate =CONVERT(datetime,'1/1/2009')

delete from h1 where  histdate>= CONVERT(datetime,'1/1/2009') and histdate<CONVERT(datetime,'6/01/2009')

Бьюсь об заклад, планы выполнения все примерно одинаковы, и использую индекс. Разница может быть в том, что количество строк в диапазоне больше, чем точное совпадение "="

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...