Liste des index inutiles

Voici une petite requête qui liste les index inutiles et présente la date de scrutation en sus des métadonnées des clauses de clef, INCLUDE et WHERE de composition de des index remontés comme inemployés.


WITH
TD AS (SELECT  create_date AS DEPUIS
       FROM    sys.databases
       WHERE   database_id = DB_ID('tempdb')),
       idc AS (SELECT ic.object_id, index_id,  
               ROW_NUMBER() OVER(PARTITION BY ic.object_id, index_id, is_included_column
                                 ORDER BY index_column_id) AS index_column_id,
               is_included_column,  
               c.name, CASE WHEN is_descending_key = 1 THEN 'DESC' ELSE 'ASC' END AS ord
        FROM   sys.index_columns AS ic
               INNER JOIN sys.columns AS c
                     ON ic.object_id = c.object_id
                        AND ic.column_id = c.column_id),
idk AS (SELECT object_id, index_id,  index_column_id, 1 as cols,
               CAST('[' + name + '] ' + ord AS NVARCHAR(max)) AS KEY_DEF
        FROM   idc        
        WHERE  is_included_column = 0
          AND  index_column_id = 1
        UNION ALL
        SELECT idc.object_id, idc.index_id, idc.index_column_id, cols + 1,
               KEY_DEF + ', ' + '[' + idc.name + '] ' + ord
        FROM   idc
               INNER JOIN idk
                     ON idc.object_id = idk.object_id AND
                     idc.index_id = idk.index_id AND
                     idc.index_column_id = idk.index_column_id + 1
        WHERE  idc.is_included_column = 0),
idi AS (SELECT object_id, index_id,  index_column_id, 1 as coli,
               CAST('[' + name + '] ' + ord AS NVARCHAR(max)) AS COL_DEF
        FROM   idc        
        WHERE  is_included_column = 1
          AND  index_column_id = 1
        UNION ALL
        SELECT idc.object_id, idc.index_id, idc.index_column_id, coli + 1,
               COL_DEF + ', ' + '[' +  idc.name + '] ' + ord
        FROM   idc
               INNER JOIN idi
                     ON idc.object_id = idi.object_id AND
                     idc.index_id = idi.index_id AND
                     idc.index_column_id = idi.index_column_id + 1
        WHERE  idc.is_included_column = 1),
dfi AS (SELECT idk.*, COL_DEF,  
               ROW_NUMBER() OVER(PARTITION BY idk.object_id, idk.index_id  
                                 ORDER BY cols DESC) AS N
        FROM   idk
               LEFT OUTER JOIN idi
                    ON idk.object_id = idi.object_id
                       AND idk.index_id = idi.index_id),
dfj AS (SELECT dfi.object_id, dfi.index_id,
               KEY_DEF AS KEY_COLUMNS,
               COL_DEF AS INCLUDED_COLUMNS, i.filter_definition AS FILTER,
               'CREATE INDEX [' + i.name + '] + ON [' + o.name +'].[' + s.name
               +'] (' + KEY_DEF +')'  
               + COALESCE(' INCLUDE (' + COL_DEF + ')', '')
               + COALESCE(' WHERE (' + i.filter_definition + ')', '') + ';' AS LOGICAL_DEFINITION                      
        FROM   dfi
               INNER JOIN sys.indexes AS i
                     ON dfi.object_id = i.object_id
                        AND dfi.index_id = i.index_id
               INNER JOIN sys.objects AS o
                     ON i.object_id = o.object_id
               INNER JOIN sys.schemas AS s
                     ON o.schema_id = s.schema_id
WHERE  N = 1)              
SELECT DEPUIS, s.name AS TABLE_SCHEMA, o.name AS TABLE_NAME, i.name AS INDEX_NAME,
       user_seeks, user_scans, user_lookups, user_updates,
       KEY_COLUMNS, INCLUDED_COLUMNS, FILTER, LOGICAL_DEFINITION
FROM   sys.dm_db_index_usage_stats AS ius
       CROSS JOIN TD
       INNER JOIN sys.indexes AS i
             ON ius.object_id = i.object_id
                AND ius.index_id = i.index_id
       INNER JOIN sys.objects AS o
             ON i.object_id = o.object_id
       INNER JOIN sys.schemas AS s
             ON o.schema_id = s.schema_id
       LEFT OUTER JOIN dfj
             ON dfj.object_id = i.object_id
                AND dfj.index_id = i.index_id                      
WHERE  database_id = DB_ID()
  AND  i.index_id > 1
  AND  user_seeks = 0
  AND  user_scans = 0
  AND  user_lookups = 0
  AND  is_unique = 0
  AND  is_primary_key = 0
  AND  is_unique_constraint = 0
ORDER BY user_updates, i.index_id DESC;

--------
Frédéric Brouard, SQLpro - ARCHITECTE DE DONNÉES, http://sqlpro.developpez.com/
Expert bases de données relationnelles et langage SQL. MVP Microsoft SQL Server
www.sqlspot.com : modélisation, conseil, audit, optimisation, tuning, formation
* * * * *  Enseignant CNAM PACA - ISEN Toulon - CESI Aix en Provence  * * * * *

MVP Microsoft SQL Server

Laisser un commentaire