[SQL]找出DB中没有使用或成本高的索引资讯

如果都没有用过的索引,也会影响保存空间及性能。所以我们将透过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;

image

以上是针对目前的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

image

如果认为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 

image

参考资讯

SQL Server DMVs in Action

sys.dm_db_index_usage_stats

SQL Server: Applying Filter on sp_MSforeachDB

原文:大专栏  [SQL]找出DB中没有使用或成本高的索引资讯


猜你喜欢

转载自www.cnblogs.com/petewell/p/11465708.html