¿Cómo encontrar índices no utilizados?

11

Estoy trabajando en un almacén de datos. Tengo tablas con hasta 200 millones de registros. Algunas de estas tablas tienen más de 20 índices (en primer lugar, no puedo proporcionar una razón por la que se crearon). Esto hace que el trabajo de mantener estos índices sea demasiado doloroso y tiene un impacto directo en el trabajo de importación de DWH tanto en el rendimiento como en el tiempo de ejecución.

¿Cómo puedo encontrar los índices menos utilizados en cada tabla? (para deshacerse de ellos)

Musulmán Ben Dhaou
fuente
2
La vista del sistema sys.dm_db_index_usage_statsproporciona esa información.
Nenad Zivkovic

Respuestas:

10

Prueba este script, me ha ayudado en el pasado:

-- 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
fuente
10

Descubrí que la secuencia de comandos BlitzIndex gratuita de Brent Ozar Unlimited (escrita por Kendra Little) es la mejor manera de aislar índices no utilizados (así como índices que son beneficiosos para agregar, índices que duplican el trabajo de otros índices, etc.)

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

Le indicará la cantidad de veces que se ha leído un índice desde la última vez que se restablecieron los recuentos estadísticos (o se creó / recreó un índice).

Me parece recordar que Brent Ozar dijo en la transmisión web que una buena regla general es no más de 10 índices para una tabla que se lee con frecuencia, 20 para las tablas que son datos estáticos / históricos / archivados que no cambiarán con frecuencia.

Si aún tiene problemas con la velocidad de importación, ¿hay un momento en que la base de datos no se consulta activamente (quizás esto sea fuera del horario de oficina). Puede ser beneficioso descartar el índice, importar los datos y luego volver a aplicar los índices. (Las estadísticas se restablecerán, por supuesto). La razón de esto es que los índices se actualizarán a medida que ingrese cada registro, las páginas se reordenarán y eso lleva tiempo y E / S de disco. Crear los índices después requiere un solo escaneo de la tabla.

Sin una regla estricta y rápida, puede que tenga que experimentar con esto dependiendo de los tipos de índice y los datos involucrados. Los índices deben revisarse periódicamente a medida que cambian las necesidades / consultas.

Greg Robson
fuente
1
Ejecuté este script pero desearía que hubiera una guía simple para interpretarlo.
IrishChieftain
0

Prueba esto:

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
fuente
0

Agregué la última fecha de uso y código para pasar a la 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
fuente