如果都没有用过的索引,也会影响保存空间及性能。所以我们将透过sys.dm_db_index_usage_stats来找出,从DB Server启动以来,从来都没有用过的索引资讯。
在“找出DB中遗漏索引的资讯”一篇中,可以找到DB中遗漏索引的资讯。
那如果都没有用过的索引,也会影响保存空间及性能。
所以我们将透过 sys.dm_db_index_usage_stats 来找出,从DB Server启动以来,从来都没有用过的索引资讯。
透过user_updates(因为数据表有做INSERT/UPDATE/DELETE所造成索引更新的次数)来找出前20个影响较大的索引资讯,如下,
SELECT TOP 20
SCHEMA_NAME(o.Schema_ID) AS SchemaName
, OBJECT_NAME(s.[object_id]) AS TableName
, i.name AS IndexName
, s.user_updates
, s.system_seeks + s.system_scans + s.system_lookups
AS [System usage]
, s.system_seeks
, s.system_scans
, s.system_lookups
FROM sys.dm_db_index_usage_stats s
INNER JOIN sys.indexes i ON s.[object_id] = i.[object_id]
AND s.index_id = i.index_id
INNER JOIN sys.objects o ON i.object_id = o.object_id
WHERE s.database_id = DB_ID()
AND OBJECTPROPERTY(s.[object_id], 'IsMsShipped') = 0
AND s.user_seeks = 0
AND s.user_scans = 0
AND s.user_lookups = 0
AND i.name IS NOT NULL
ORDER BY s.user_updates DESC;
以上是针对目前的DB查询,如果要一次找多个DB的话,可以透过 sp_MSforeachdb 和 temp table来保存所有DB的索引资讯,如下,
SELECT
DB_NAME() AS DatabaseName
, SCHEMA_NAME(o.Schema_ID) AS SchemaName
, OBJECT_NAME(s.[object_id]) AS TableName
, i.name AS IndexName
, s.user_updates
, s.system_seeks + s.system_scans + s.system_lookups
AS [System usage]
, s.system_seeks
, s.system_scans
, s.system_lookups
INTO #TempUnusedIndexes
FROM sys.dm_db_index_usage_stats s
INNER JOIN sys.indexes i ON s.[object_id] = i.[object_id]
AND s.index_id = i.index_id
INNER JOIN sys.objects o ON i.object_id = o.object_id
WHERE 1=2
EXEC sp_MSforeachdb 'USE [?];
INSERT INTO #TempUnusedIndexes
SELECT TOP 20
DB_NAME() AS DatabaseName
, SCHEMA_NAME(o.Schema_ID) AS SchemaName
, OBJECT_NAME(s.[object_id]) AS TableName
, i.name AS IndexName
, s.user_updates
, s.system_seeks + s.system_scans + s.system_lookups
AS [System usage]
, s.system_seeks
, s.system_scans
, s.system_lookups
FROM sys.dm_db_index_usage_stats s
INNER JOIN sys.indexes i ON s.[object_id] = i.[object_id]
AND s.index_id = i.index_id
INNER JOIN sys.objects o ON i.object_id = o.object_id
WHERE s.database_id = DB_ID()
AND OBJECTPROPERTY(s.[object_id], ''IsMsShipped'') = 0
AND s.user_seeks = 0
AND s.user_scans = 0
AND s.user_lookups = 0
AND i.name IS NOT NULL
ORDER BY s.user_updates DESC'
SELECT * FROM #TempUnusedIndexes ORDER BY [user_updates] DESC
DROP TABLE #TempUnusedIndexes
如果认为DB Server启动以来,系统大多数的功能都使用过了,那就可以将上面找出的索引删除或是停用,以减少保存空间及提升性能。
MSDN user_updates 的说明如下,
会指出索引上由基础数据表或检视的插入、更新或删除作业所导致的维护层级。
您可以利用这份检视来判断应用程序根本很少用到的索引。
您也可以利用这份检视,来判断哪些索引会产生维护负担。
您可能会考虑卸除产生维护负担,但不用于查询,或者不常用于查询的索引。
所以也可以透过 user_updates - user_seeks - user_scans - user_lookups 的计算,也可以找出成本比较高的索引是那些,如下,
SELECT TOP 20
SCHEMA_NAME(o.Schema_ID) AS SchemaName
, OBJECT_NAME(s.[object_id]) AS TableName
, i.name AS IndexName
, (s.user_updates ) AS [update usage]
, (s.user_seeks + s.user_scans + s.user_lookups)
AS [Retrieval usage]
, (s.user_updates - s.user_seeks - user_scans - s.user_lookups)
AS [Maintenance cost]
, s.system_seeks + s.system_scans + s.system_lookups AS [System usage]
, s.last_user_seek
, s.last_user_scan
, s.last_user_lookup
FROM sys.dm_db_index_usage_stats s
INNER JOIN sys.indexes i ON s.[object_id] = i.[object_id]
AND s.index_id = i.index_id
INNER JOIN sys.objects o ON i.object_id = o.object_id
WHERE s.database_id = DB_ID()
AND i.name IS NOT NULL
AND OBJECTPROPERTY(s.[object_id], 'IsMsShipped') = 0
AND (s.user_seeks + s.user_scans + s.user_lookups) > 0
ORDER BY [Maintenance cost] DESC
参考资讯
SQL Server DMVs in Action
sys.dm_db_index_usage_stats
SQL Server: Applying Filter on sp_MSforeachDB
原文:大专栏 [SQL]找出DB中没有使用或成本高的索引资讯