MSSQL:last_user_update是否意味着索引损害了性能?

时间:2009-06-01 09:56:43

标签: sql-server performance maintenance

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

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 

2 个答案:

答案 0 :(得分: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,50G左右数据库,我们之前使用过这个数据效果很好)

来自sys.dm_db_index_usage_stats

  

user_updates计数器指示   索引的维护级别   由插入,更新或删除引起的   基础表上的操作或   视图。您可以使用此视图   确定仅使用哪些索引   轻轻地通过您的应用程序。您可以   还使用视图来确定哪个   索引正在进行维护   高架。你可能想考虑一下   丢弃引发的索引   维护开销,但未使用   用于查询,或者很少查询   用于查询。

所以,最后一句话意味着要看看用法和更新

答案 1 :(得分:1)

如果您对索引的动态属性感兴趣 - 无论它们是否被使用 - 您可能最好在DMV中查询Dynamic Management Views。他们应该为您提供有关使用哪些索引以及使用频率的详细信息。

此外,还有一个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