0

我编写了一个查询来查找在生产环境中未使用的索引以删除它们,但是我很好奇该last_user_update列是否表明索引只是维护开销,在这种情况下它将是删除它很好,或者索引是否有助于插入/更新/删除语句的性能,在这种情况下我不想删除它。以下是我想使用的查询:

DECLARE @DBInfo TABLE  
( database_id int, object_id int, tablename nvarchar(200), indexname nvarchar(200), lastactivity datetime)  

DECLARE @command VARCHAR(5000)  

SELECT @command = 'Use [' + '?' + '] SELECT  
database_id, o.object_id, o.name, i.name as indexname, max(lastactivity) as lastactivity
from (
    select database_id, object_id, index_id, max(last_user_seek) as lastactivity from sys.dm_db_index_usage_stats
    WHERE object_id > 1000
    GROUP BY database_id, object_id, index_id
    UNION ALL
    select database_id, object_id, index_id, max(last_user_scan) as lastactivity from sys.dm_db_index_usage_stats
    WHERE object_id > 1000
    GROUP BY database_id, object_id, index_id
    UNION ALL
    select database_id, object_id, index_id, max(last_user_lookup) as lastactivity from sys.dm_db_index_usage_stats
    WHERE object_id > 1000
    GROUP BY database_id, object_id, index_id
    /*UNION ALL
    select database_id, object_id, index_id, max(last_user_update) as lastactivity from sys.dm_db_index_usage_stats
    WHERE object_id > 1000
    GROUP BY database_id, object_id, index_id*/
) a
inner join sys.objects o on a.object_id = o.object_id
inner join sys.indexes i on i.object_id = a.object_id AND i.index_id = a.index_id
where database_id = db_id()
GROUP BY database_id, o.object_id, o.name, i.name
order by lastactivity'  
INSERT INTO @DBInfo  
   (database_id, object_id, tablename, indexname, lastactivity)  
EXEC sp_MSForEachDB @command  

SELECT db_name(database_id) as dbname, tablename, indexname, lastactivity FROM @DBInfo
where lastactivity < dateadd(day, -15, getdate()) or lastactivity is null
order by db_name(database_id), tablename, indexname 
4

2 回答 2

2

该列在检查未使用的索引时没有任何实际意义。

索引可能没有最近的更新,但仍然非常有用(例如,避免表扫描或覆盖流行的查询)。此查询告诉您如何使用索引:

SELECT
    o.name AS [object_name], 
    i.name AS index_name, 
    i.type_desc, 
    u.user_seeks, u.user_scans, 
    u.user_lookups, u.user_updates,
    o.type
FROM
    sys.indexes i
    JOIN
    sys.objects o ON i.[object_id] = o.[object_id]
    LEFT JOIN 
    sys.dm_db_index_usage_stats u ON i.[object_id] = u.[object_id] AND 
                                    i.index_id = u.index_id AND 
                                    u.database_id = DB_ID()
WHERE
    o.type IN ('U', 'V') AND
    i.name IS NOT NULL
ORDER BY 
    o.name, i.NAME;

编辑,评论后:

我更喜欢user_seeks, user_scans, user_lookups and user_updates告诉我如何使用索引的列。仅供参考,我使用了上面的查询并包含“system_updates”列,但所有值都为零(SQL 2005、50Gb 左右的数据库,我们之前使用过这个效果很好)

sys.dm_db_index_usage_stats

user_updates 计数器指示由对基础表或视图的插入、更新或删除操作引起的索引维护级别。您可以使用此视图来确定哪些索引仅由您的应用程序轻度使用。您还可以使用该视图来确定哪些索引会产生维护开销。您可能需要考虑删除会导致维护开销但不用于查询或仅不经常用于查询的索引。

所以,最后一句话意味着要查看使用情况和更新

于 2009-06-01T10:21:45.587 回答
1

如果你对索引的动态属性感兴趣——无论它们是否被使用——你最好在 DMV 中查询——动态管理视图。他们应该为您提供有关正在使用哪些索引以及使用频率的很好的信息。

此外,还有一个 DMV 实际上使用查询优化器的内部统计信息来建议 a) 可能有助于提高性能的可能丢失的索引,以及 b) 另一个显示可能未使用的索引。

请注意-这些是动态管理视图-每次服务器重新启动时都会重置它们,因此它们不会在永恒的时间段内收集数据-仅在您上次重置后。

马克

查找缺失的索引:

SELECT  
    object_name(object_id), d.*, s.*
FROM
    sys.dm_db_missing_index_details d 
INNER JOIN 
    sys.dm_db_missing_index_groups g ON d.index_handle = g.index_handle
INNER JOIN 
    sys.dm_db_missing_index_group_stats s ON    g.index_group_handle = s.group_handle
WHERE   
    database_id = db_id()
ORDER BY  
    object_id

查找未使用的索引:

DECLARE  @dbid INT

SELECT @dbid = DB_ID(DB_NAME())

SELECT   
    OBJECTNAME = OBJECT_NAME(I.OBJECT_ID),
    INDEXNAME = I.NAME,
    I.INDEX_ID
FROM     
    SYS.INDEXES I
JOIN 
    SYS.OBJECTS O ON I.OBJECT_ID = O.OBJECT_ID
WHERE    
    OBJECTPROPERTY(O.OBJECT_ID, 'IsUserTable') = 1
    AND I.INDEX_ID NOT IN (SELECT S.INDEX_ID
                            FROM SYS.DM_DB_INDEX_USAGE_STATS S
                            WHERE S.OBJECT_ID = I.OBJECT_ID
                                    AND I.INDEX_ID = S.INDEX_ID
                                    AND DATABASE_ID = @dbid)
ORDER BY 
    OBJECTNAME,
    I.INDEX_ID,
    INDEXNAME ASC
于 2009-06-01T10:29:46.523 回答