Самый быстрый 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. Это поможет вам увидеть, какой индекс будет использоваться. После добавления индекса вы можете выполнить запрос и оценить результаты с помощью плана выполнения. И, конечно же, наблюдение прошедшего времени тоже поможет.

Другие вопросы по тегам