SQL データベース内の未使用のインデックスを監視して見つけるにはどうすればよいですか

StackOverflow https://stackoverflow.com/questions/1456496

質問

未使用のインデックスを見つけて削除するために、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 以降で機能することに注意してください。鍵となるのは、 JOINSYS.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は何を探すために、問題を処理する方法を説明している与えられます。

ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top