Ole*_*nge 9 sql-server indexing maintenance
我想监视sql数据库的索引使用情况,以便找到未使用的索引,然后删除它们.如何最有效地监控索引使用情况?哪些脚本可能有用?
(我知道有关识别未使用对象的问题,但这仅适用于sql server的当前运行.我想监视一段时间内的索引使用情况......)
目前(从SQL Server 2005 - 2008开始),SQL索引统计信息仅保留在内存中,因此如果您希望在重新启动和数据库分离时保持这种状态,则必须自己完成一些工作.
我通常做的是,我创建一个每天运行的作业,并将sys.dm_db_index_usage_stats表中的信息快照放入我为相关数据库创建的自定义表中.
这似乎很有效,直到将来支持持久索引使用统计数据的SQL的未来版本.
这是个有趣的问题.过去一周我一直在研究同样的问题.有一个名为dm_db_index_usage_stats的系统表,其中包含索引的使用情况统计信息.
使用统计表中从不出现的索引
但是,许多索引根本不会出现在此表中.David Andres发布的查询列出了此案例的所有索引.我已经更新了一点点忽略了主键,这些主键可能不应该删除,即使它们从未被使用过.我还加入了dm_db_index_physical_stats表以获取其他信息,包括页面计数,总索引大小和碎片百分比.一个有趣的注意事项是,此查询返回的索引似乎未显示在"索引使用情况统计信息的SQL报告"中.
DECLARE @dbid INT
SELECT @dbid = DB_ID(DB_NAME())
SELECT Databases.Name AS [Database],
Objects.NAME AS [Table],
Indexes.NAME AS [Index],
Indexes.INDEX_ID,
PhysicalStats.page_count as [Page Count],
CONVERT(decimal(18,2), PhysicalStats.page_count * 8 / 1024.0) AS [Total Index Size (MB)],
CONVERT(decimal(18,2), PhysicalStats.avg_fragmentation_in_percent) AS [Fragmentation (%)]
FROM SYS.INDEXES Indexes
INNER JOIN SYS.OBJECTS Objects ON Indexes.OBJECT_ID = Objects.OBJECT_ID
LEFT JOIN sys.dm_db_index_physical_stats(@dbid, null, null, null, null) PhysicalStats
on PhysicalStats.object_id = Indexes.object_id and PhysicalStats.index_id = indexes.index_id
INNER JOIN sys.databases Databases
ON Databases.database_id = PhysicalStats.database_id
WHERE OBJECTPROPERTY(Objects.OBJECT_ID,'IsUserTable') = 1
AND Indexes.type = 2 -- Nonclustered indexes
AND Indexes.INDEX_ID NOT IN (
SELECT UsageStats.INDEX_ID
FROM SYS.DM_DB_INDEX_USAGE_STATS UsageStats
WHERE UsageStats.OBJECT_ID = Indexes.OBJECT_ID
AND Indexes.INDEX_ID = UsageStats.INDEX_ID
AND DATABASE_ID = @dbid)
ORDER BY PhysicalStats.page_count DESC,
Objects.NAME,
Indexes.INDEX_ID,
Indexes.NAME ASC
Run Code Online (Sandbox Code Playgroud)
在使用情况统计表中出现的索引,但从未使用过
还有其他索引确实出现在dm_db_index_usage_stats表中,但从未用于用户搜索,扫描或查找.此查询将标识属于此类别的索引.顺便提一下,与从其他查询返回的索引不同,此查询中返回的索引可以通过索引使用情况统计信息在SQL报告上进行验证.
我添加了一个最小页数,允许我最初关注并删除占用大量存储空间的未使用索引.
DECLARE @MinimumPageCount int
SET @MinimumPageCount = 500
SELECT Databases.name AS [Database],
Indexes.name AS [Index],
Objects.Name AS [Table],
PhysicalStats.page_count as [Page Count],
CONVERT(decimal(18,2), PhysicalStats.page_count * 8 / 1024.0) AS [Total Index Size (MB)],
CONVERT(decimal(18,2), PhysicalStats.avg_fragmentation_in_percent) AS [Fragmentation (%)],
ParititionStats.row_count AS [Row Count],
CONVERT(decimal(18,2), (PhysicalStats.page_count * 8.0 * 1024) / ParititionStats.row_count) AS [Index Size/Row (Bytes)]
FROM sys.dm_db_index_usage_stats UsageStats
INNER JOIN sys.indexes Indexes
ON Indexes.index_id = UsageStats.index_id
AND Indexes.object_id = UsageStats.object_id
INNER JOIN sys.objects Objects
ON Objects.object_id = UsageStats.object_id
INNER JOIN SYS.databases Databases
ON Databases.database_id = UsageStats.database_id
INNER JOIN sys.dm_db_index_physical_stats (DB_ID(), NULL, NULL, NULL, NULL) AS PhysicalStats
ON PhysicalStats.index_id = UsageStats.Index_id
and PhysicalStats.object_id = UsageStats.object_id
INNER JOIN SYS.dm_db_partition_stats ParititionStats
ON ParititionStats.index_id = UsageStats.index_id
and ParititionStats.object_id = UsageStats.object_id
WHERE UsageStats.user_scans = 0
AND UsageStats.user_seeks = 0
AND UsageStats.user_lookups = 0
AND PhysicalStats.page_count > @MinimumPageCount -- ignore indexes with less than 500 pages of memory
AND Indexes.type_desc != 'CLUSTERED' -- Exclude primary keys, which should not be removed
ORDER BY [Page Count] DESC
Run Code Online (Sandbox Code Playgroud)
我希望这有帮助.
最后的想法
当然,一旦确定索引作为删除的候选人,仍应仔细考虑,以确保这是一个很好的决定.
有关更多信息,请参阅识别SQL Server数据库中未使用的索引
| 归档时间: |
|
| 查看次数: |
12860 次 |
| 最近记录: |