11

未使用のインデックスを見つけて削除するために、SQL データベースのインデックスの使用状況を監視したいと考えています。インデックスの使用状況を最も効率的に監視するにはどうすればよいですか? また、どのスクリプトが役に立ちますか?

(使用されていないオブジェクトの識別に関するこの質問は承知していますが、これは SQL サーバーの現在の実行にのみ適用されます。一定期間にわたってインデックスの使用状況を監視したいと思います...)

4

5 に答える 5

8

これは興味深い質問です。私は先週、この同じ質問に取り組んできました。インデックスの使用統計を含む 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

使用状況統計テーブルには表示されるが、使用されないインデックス

dm_db_index_usage_stats テーブルに表示されるインデックスは他にもありますが、ユーザーのシーク、スキャン、またはルックアップには使用されていません。このクエリは、このカテゴリに分類されるインデックスを識別します。ちなみに、他のクエリから返されたインデックスとは異なり、このクエリで返されたインデックスは、Index Usage Statistics によって 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 データベースで未使用のインデックスを特定する」を参照してください。

于 2012-12-14T16:13:20.390 に答える
7

現在 (SQL Server 2005 ~ 2008 の時点)、SQL インデックスの統計情報はメモリにのみ保持されているため、再起動やデータベースの切断後も保持したい場合は、自分でいくつかの作業を行う必要があります。

私が通常行うことは、毎日実行するジョブを作成し、sys.dm_db_index_usage_statsテーブルで見つかった情報のスナップショットを、問題のデータベース用に作成するカスタム テーブルに作成することです。

これは、永続的なインデックス使用統計をサポートする予定の SQL の将来のバージョンまで、かなりうまく機能するようです。

于 2009-09-21T19:58:38.073 に答える
3

この子犬を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
于 2009-09-21T20:00:18.697 に答える
1

Brent Ozars のsp_BlitzIndexを見てください。このストアド プロシージャには、使用されていないインデックスが一覧表示されます。レポート内の障害を一覧表示します。各エントリには、検索対象と問題の処理方法を説明する URL が示されています。

于 2015-10-01T05:38:09.527 に答える