Como encontrar índices não utilizados?

11

Estou trabalhando em um data warehouse. Eu tenho tabelas com até 200 milhões de registros. Algumas dessas tabelas têm mais de 20 índices (não posso fornecer uma razão pela qual eles foram criados em primeiro lugar). Isso está tornando o trabalho de manter esses índices muito dolorosos e tem um impacto direto no trabalho de importação do DWH no desempenho e no tempo de execução.

Como posso encontrar os índices menos usados ​​em cada tabela? (para se livrar deles)

Muçulmano Ben Dhaou
fonte
2
A exibição do sistema sys.dm_db_index_usage_statsfornece essas informações.
Nenad Zivkovic

Respostas:

10

Experimente este script, ele me ajudou no passado:

-- 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/

Paul White 9
fonte
10

Descobri que o script BlitzIndex gratuito do Brent Ozar Unlimited (escrito por Kendra Little) é a melhor maneira de isolar índices não utilizados (bem como índices que são benéficos para serem adicionados, índices que estão duplicando o trabalho de outros índices etc.)

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

Ele informará o número de vezes que um índice foi lido desde a última vez em que as contagens estatísticas foram redefinidas (ou um índice foi criado / recriado).

Eu me lembro de Brent Ozar dizendo no webcast que uma boa regra geral é não mais do que 10 índices para uma tabela que é lida frequentemente, 20s para tabelas que são dados estáticos / históricos / arquivados que não mudam com freqüência.

Se você ainda está tendo problemas com a velocidade de importação, existe um momento em que o banco de dados não está sendo consultado ativamente (talvez esteja fora do horário comercial). Pode ser benéfico eliminar o índice, importar os dados e reaplicar os índices. (As estatísticas serão redefinidas, é claro.) O motivo é que os índices serão atualizados à medida que cada registro entra, as páginas são reordenadas e isso leva tempo e E / S do disco. Construir os índices depois requer uma única varredura da tabela.

Nenhuma regra rígida e rápida, você pode ter que experimentar isso dependendo dos tipos de índice e dos dados envolvidos. Os índices devem ser revisados ​​regularmente conforme as necessidades / consultas mudam.

Greg Robson
fonte
1
Eu executei esse script, mas gostaria que houvesse um guia simples para interpretá-lo.
IrishChieftain
0

Tente o seguinte:

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 

Raj

Raj
fonte
0

Adicionei a data e o código da última vez em que foi usado na consulta de Raj.

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
Mike Nelson
fonte