Самый быстрый SQL-запрос для неиндексированных данных
Я создаю несколько пользовательских отчетов для базы данных SQL Server 2005. База данных принадлежит стороннему управляющему приложению. Данные, которые я извлекаю, не относятся к основным целям сайта, поэтому данные в основном не индексируются, за исключением столбца меток времени. На данный момент задействована только одна таблица - таблица из 700 миллионов строк. Поэтому, когда я запускаю запрос к нему, который должен вернуть только 50 строк, он должен опросить все 700 миллионов.
Я хочу ускорить это, но не хочу индексировать каждый столбец, который добавляю в предложение WHERE - я не знаю, что добавление такого количества индексов приведет к значительному повышению скорости (или я неправильно?). Поэтому мне любопытно, что будет лучше, если я не смогу добавить новые индексы в таблицу!
Хранимая процедура не выглядит наилучшим образом. Индексированное представление может быть лучшей идеей? Мысли?
Вот схема таблицы:
DeviceGuid (PK, uniqueidentifier, not null)
DeviceID (int, not null)
WindowsEventID (PK, int, not null) (indexed)
EventLog (varchar(64), not null)
EventSource (varchar(64), not null)
EventID (int, not null)
Severity (int, not null)
Description (nvarchar(max), not null)
TimeOfEvent (PK, datetime, not null) (indexed)
OccurrenceNbr (int, not null)
Вот пример запроса:
SELECT COUNT(*) AS NumOcc, EventID, EventLog, EventSource, Severity, TimeOfEvent, Description
FROM WindowsEvent
WHERE DeviceID='34818'
AND Severity=1
AND TimeOfEvent >= DATEADD(hh, DATEDIFF(hh, GETDATE(), GETUTCDATE()), '2010/10/27 12:00:00 AM')
AND TimeOfEvent <= DATEADD(hh, DATEDIFF(hh, GETDATE(), GETUTCDATE()), '2010/11/3 12:00:00 AM')
AND EventID<>34113
AND EventID<>34114
AND EventID<>34112
AND EventID<>57755
AND EventSource<>'AutoImportSvc.exe'
AND EventLog='Application'
GROUP BY EventID, EventLog, EventSource, Severity, Description
ORDER BY NumOcc DESC
Может быть, запрос отстой... он возвращает 53 строки за 4,5 минуты.
4 ответа
Окончательное решение здесь состояло в том, чтобы выполнить запрос к индексированным полям, а затем отфильтровать их в приложении, выполняющем запрос. Два поля содержали достаточно схожую информацию, которую я мог запросить по одному индексу и получить очень близкое приближение к нужным данным. Я перебрал и удалил все несоответствующие объекты из списка результатов. Прошло НАМНОГО меньше времени!
Это довольно просто, но я бы попробовал индексированное значение в качестве первого теста в
Попробуйте этот метод, используя двойной трюк row_number:
SELECT RN_Desc as NumOcc, *
FROM (
SELECT row_number() Over(partition by EventId order by EventLog, EventSource, Severity, Description) as RN_Asc,
row_number() Over(partition by EventId order by EventLog desc, EventSource desc, Severity desc, Description desc) as RN_Desc,
*
FROM WindowsEvent
WHERE DeviceID='34818'
AND Severity=1
AND TimeOfEvent >= DATEADD(hh, DATEDIFF(hh, GETDATE(), GETUTCDATE()), '2010/10/27 12:00:00 AM')
AND TimeOfEvent <= DATEADD(hh, DATEDIFF(hh, GETDATE(), GETUTCDATE()), '2010/11/3 12:00:00 AM')
AND EventID<>34113
AND EventID<>34114
AND EventID<>34112
AND EventID<>57755
AND EventSource<>'AutoImportSvc.exe'
AND EventLog='Application'
) t
WHERE RN_Asc = 1
ORDER BY NumOcc DESC
с этим движку не нужно делать никаких агрегаций, только один проход по таблице. если это не работает, попробуйте поиграть с порядком и разделить по частям, чтобы получить правильные группировки.
Если ваш запрос не использует индексы, это будет очень плохо. Вам не нужен индекс для каждого столбца, но вам нужен индекс в правом столбце. Учитывая, что TimeOfEvent уже проиндексирован, он может не подойти для ваших нужд.
Правая колонка будет зависеть от распределения ваших данных. Наилучшим индексом, вероятно, будет индекс, обеспечивающий наивысшую селективность (т. Е. Когда вы знаете значение ключа для индекса, он возвращает наименьшее количество строк). Если вам известен столбец, обеспечивающий наилучшую селективность, вы можете попробовать индекс по нему.
Чтобы помочь определить лучший индекс, вы можете использовать Просмотр оценочного плана выполнения в SSMS. Это поможет вам увидеть, какой индекс будет использоваться. После добавления индекса вы можете выполнить запрос и оценить результаты с помощью плана выполнения. И, конечно же, наблюдение прошедшего времени тоже поможет.