我编写了一个查询来查找生产环境中未使用的索引以便删除它们,但是我很好奇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
答案 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左右数据库,我们之前使用过这个数据效果很好)
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