SQL データベース内の未使用のインデックスを監視して見つけるにはどうすればよいですか
-
12-09-2019 - |
質問
未使用のインデックスを見つけて削除するために、SQL データベースのインデックスの使用状況を監視したいと考えています。インデックスの使用状況を最も効率的に監視するにはどうすればよいですか?そして、どのスクリプトが役立つでしょうか?
(承知しております 未使用オブジェクトの識別に関するこの質問, ただし、これは SQL サーバーの現在の実行にのみ適用されます。一定期間にわたってインデックスの使用状況を監視したいと考えています...)
解決
現在(SQL Server 2005ののように - 2008)。SQLインデックスは情報のみをメモリに保持されるので、あなたが再起動しても持続し、データベースをデタッチことがしたい場合は、作業を自分でのいくつかをしなければならない統計
私は通常何、私は毎日を実行し、私は問題のデータベースのために作成したカスタムテーブルに、sys.dm_db_index_usage_stats
テーブルで見つかった情報のスナップショットを取りジョブを作成されます。
これは、永続的なインデックスの使用状況の統計をサポートするSQLの将来のバージョンまではかなりうまく動作するようです。
他のヒント
これは興味深い質問です。できないかなぁ、とおもってこの問題は、過去ます。あるシステムテーブルと呼ばれdm_db_index_usage_statsる利用統計スを作成します。
インデックスに表示されることはありません利用統計表
しかし、多くの指標を見ることがこのテーブルです。クエリのデビッド-アンドレス投稿リストのすべての指標です。更新しましたちょっと無視する主キー、おそらくはないので、削除するものがない場合も使用します。私も参加し、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
指標との利用統計表のものを利用したことのない
ありその他の指標と表示され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
この助けになっていますよ。
最終的思考
もちろん、一度指標にすることを目的として、 候補者 のための除去、注意深く考慮する必要があります採用してください良い決断です。
詳細については、 特定未使用の指標は、SQL Serverデータベース
この子犬を引き離した http://blog.sqlauthority.com/2008/02/11/sql-server-2005-find-unused-indexes-of-current-database/. 。これは 2005 以降で機能することに注意してください。鍵となるのは、 JOIN
に SYS.DM_DB_INDEX_USAGE_STATS
システムテーブル。
USE AdventureWorks
GO
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
GO
私はここでジョンPasquetのクエリを微調整:インデックスを返すために、SQL Serverデータベースの中で未使用のインデックスを10倍以下を使用識別、使用統計情報の表にない結果をUNION句、ヒープのインデックスとユニーク制約または主キーのインデックスを除外し、最終的にインデックスを除外するためにゼロページを持ちます。
このクエリの結果には注意してください - それは、インデックスが実際にあなたが期待する道を慣れているところの生産に使用することをお勧めします。あなたが再構築または削除/再作成インデックスのデータベース上または最近のデータベースのバックアップに照会する場合は、偽陽性(通常使用されるが、特別の事情がある場合においてはないになるだろうインデックス)を得ることができます。インデックスを削除するかどうかを決定するために、テストまたはDEV環境で安全に使用できません。 Narnianが言うように、このクエリは、ちょうどあなたの慎重な検討のための除去のための候補者を識別します。
USE [DatabaseName]
DECLARE @MinimumPageCount int
SET @MinimumPageCount = 500
DECLARE @dbid INT
SELECT @dbid = DB_ID(DB_NAME())
-- GET UNUSED INDEXES THAT APPEAR IN THE INDEX USAGE STATS TABLE
SELECT
Databases.name AS [Database]
,object_name(Indexes.object_id) AS [Table]
,Indexes.name AS [Index]
,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 Per Row (Bytes)]
,1 AS [Appears In Usage Stats Table]
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.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 <= 10
AND UsageStats.user_seeks <= 10
AND UsageStats.user_lookups <= 10
-- exclude heap indexes
AND Indexes.name IS NOT NULL
-- ignore indexes with less than a certain number of pages of memory
AND PhysicalStats.page_count > @MinimumPageCount
-- Exclude primary keys, which should not be removed
AND Indexes.is_primary_key = 0
-- ignore unique constraints - those shouldn't be removed
AND Indexes.is_unique_constraint = 0
AND Indexes.is_unique = 0
UNION ALL
(
-- GET UNUSED INDEXES THAT DO **NOT** APPEAR IN THE INDEX USAGE STATS TABLE
SELECT
Databases.Name AS [Database]
,Objects.NAME AS [Table]
,Indexes.NAME AS [Index]
,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 (%)]
,-1 AS [Row Count]
,-1 AS [Index Size Per Row (Bytes)]
,0 AS [Appears In Usage Stats Table]
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
Objects.type = 'U' -- Is User Table
-- exclude heap indexes
AND Indexes.name IS NOT NULL
-- exclude empty tables
AND PhysicalStats.page_count <> 0
-- Exclude primary keys, which should not be removed
AND Indexes.is_primary_key = 0
-- ignore unique constraints - those shouldn't be removed
AND Indexes.is_unique_constraint = 0
AND Indexes.is_unique = 0
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 [Table] ASC, [Total Index Size (MB)] DESC
あなたはブレントOzars sp_BlitzIndex のを見てみる必要があります。このストアドプロシージャは、他unsusedインデックスの中で示しています。これは、レポート内の障害を示しています。各エントリのURLは何を探すために、問題を処理する方法を説明している与えられます。