Как найти неиспользуемые индексы?

11

Я работаю над хранилищем данных. У меня есть таблицы с записями до 200 миллионов. Некоторые из этих таблиц имеют более 20 индексов (я не могу указать причину, почему они были созданы в первую очередь). Это делает работу по поддержанию этих индексов слишком болезненной и оказывает непосредственное влияние на работу импорта DWH как по производительности, так и по времени выполнения.

Как найти наименее используемые индексы для каждой таблицы? (чтобы избавиться от них)

Мусульманин Бен Дхау
источник
2
Системное представление sys.dm_db_index_usage_statsпредоставляет эту информацию.
Ненад Живкович

Ответы:

10

Попробуйте этот скрипт, он помог мне в прошлом:

-- Unused Index Script
-- Original Author: Pinal Dave 
SELECT TOP 25
o.name AS ObjectName
, i.name AS IndexName
, i.index_id AS IndexID
, dm_ius.user_seeks AS UserSeek
, dm_ius.user_scans AS UserScans
, dm_ius.user_lookups AS UserLookups
, dm_ius.user_updates AS UserUpdates
, p.TableRows
, 'DROP INDEX ' + QUOTENAME(i.name)
+ ' ON ' + QUOTENAME(s.name) + '.'
+ QUOTENAME(OBJECT_NAME(dm_ius.OBJECT_ID)) AS 'drop statement'
FROM sys.dm_db_index_usage_stats dm_ius
INNER JOIN sys.indexes i ON i.index_id = dm_ius.index_id 
AND dm_ius.OBJECT_ID = i.OBJECT_ID
INNER JOIN sys.objects o ON dm_ius.OBJECT_ID = o.OBJECT_ID
INNER JOIN sys.schemas s ON o.schema_id = s.schema_id
INNER JOIN (SELECT SUM(p.rows) TableRows, p.index_id, p.OBJECT_ID
FROM sys.partitions p GROUP BY p.index_id, p.OBJECT_ID) p
ON p.index_id = dm_ius.index_id AND dm_ius.OBJECT_ID = p.OBJECT_ID
WHERE OBJECTPROPERTY(dm_ius.OBJECT_ID,'IsUserTable') = 1
AND dm_ius.database_id = DB_ID()
AND i.type_desc = 'nonclustered'
AND i.is_primary_key = 0
AND i.is_unique_constraint = 0
ORDER BY (dm_ius.user_seeks + dm_ius.user_scans + dm_ius.user_lookups) ASC

http://blog.sqlauthority.com/2011/01/04/sql-server-2008-unused-index-script-download/

Пол Уайт 9
источник
10

Я обнаружил, что бесплатный скрипт BlitzIndex от Brent Ozar Unlimited (написанный Кендрой Литтлом) - лучший способ изолировать неподдерживаемые индексы (а также индексы, которые выгодно добавлять, индексы, дублирующие работу других индексов и т. Д.)

http://www.brentozar.com/blitzindex/

Он сообщит вам количество раз, когда какой-либо индекс был прочитан с момента последнего сброса статистических показателей (или создания / повторного создания индекса).

Кажется, я помню, как Брент Озар говорил в веб-трансляции, что хорошее эмпирическое правило - не более 10 индексов для таблицы, которую часто читают, и 20 для таблиц, которые представляют собой статические / исторические / архивные данные, которые не будут часто меняться.

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

Нет жесткого и быстрого правила, вам, возможно, придется экспериментировать с этим в зависимости от типов индекса и задействованных данных. Индексы должны регулярно пересматриваться по мере изменения потребностей / запросов.

Грег Робсон
источник
1
Я запустил этот скрипт, но хотелось бы, чтобы было простое руководство по его интерпретации.
IrishChieftain
0

Попробуй это:

SELECT   OBJECT_NAME(S.[OBJECT_ID]) AS [OBJECT NAME], 
             I.[NAME] AS [INDEX NAME], 
             USER_SEEKS, 
             USER_SCANS, 
             USER_LOOKUPS, 
             USER_UPDATES 
    FROM     SYS.DM_DB_INDEX_USAGE_STATS AS S 
             INNER JOIN SYS.INDEXES AS I 
               ON I.[OBJECT_ID] = S.[OBJECT_ID] 
                  AND I.INDEX_ID = S.INDEX_ID 
    WHERE    OBJECTPROPERTY(S.[OBJECT_ID],'IsUserTable') = 1 

Радж

Радж
источник
0

Я добавил последнюю использованную дату и код для перехода к запросу Радж.

SELECT   OBJECT_NAME(S.[OBJECT_ID]) AS [OBJECT NAME], 
             I.[NAME] AS [INDEX NAME], type_desc,
             coalesce(last_user_seek,last_user_scan,last_user_lookup,last_system_scan,last_system_seek,last_system_lookup) as LastUsed,
             USER_SEEKS, 
             USER_SCANS, 
             USER_LOOKUPS, 
             USER_UPDATES ,
             last_user_seek,last_user_scan,last_user_lookup,last_system_scan,last_system_seek,last_system_lookup,
             'drop index ['+I.[NAME]+'] on ['+OBJECT_NAME(S.[OBJECT_ID])+'];' as DropStatement
    FROM     SYS.DM_DB_INDEX_USAGE_STATS AS S 
             INNER JOIN SYS.INDEXES AS I 
               ON I.[OBJECT_ID] = S.[OBJECT_ID] 
                  AND I.INDEX_ID = S.INDEX_ID 
    WHERE    OBJECTPROPERTY(S.[OBJECT_ID],'IsUserTable') = 1 
    order by type_desc,coalesce(last_user_seek,last_user_scan,last_user_lookup,last_system_scan,last_system_seek,last_system_lookup) desc
Майк Нельсон
источник