未使用のインデックスを見つける方法は?


11

私はデータウェアハウスに取り組んでいます。最大2億レコードのテーブルがあります。これらのテーブルの一部には約20以上のインデックスがあります(そもそもそれらが作成された理由を説明することはできません)。これにより、これらのインデックスを維持する作業が非常に面倒になり、パフォーマンスとランタイムの両方でDWHインポートジョブに直接影響を与えます。

各テーブルで最も使用されていないインデックスを見つけるにはどうすればよいですか?(それらを取り除くために)


2
システムビューsys.dm_db_index_usage_statsはその情報を提供します。
Nenad Zivkovic 2013

回答:


10

このスクリプトを試してください、それは過去に私を助けました:

-- Unused Index Script
-- Original Author: Pinal Dave 
SELECT TOP 25
o.name AS ObjectName
, i.name AS IndexName
, i.index_id AS IndexID
, dm_ius.user_seeks AS UserSeek
, dm_ius.user_scans AS UserScans
, dm_ius.user_lookups AS UserLookups
, dm_ius.user_updates AS UserUpdates
, p.TableRows
, 'DROP INDEX ' + QUOTENAME(i.name)
+ ' ON ' + QUOTENAME(s.name) + '.'
+ QUOTENAME(OBJECT_NAME(dm_ius.OBJECT_ID)) AS 'drop statement'
FROM sys.dm_db_index_usage_stats dm_ius
INNER JOIN sys.indexes i ON i.index_id = dm_ius.index_id 
AND dm_ius.OBJECT_ID = i.OBJECT_ID
INNER JOIN sys.objects o ON dm_ius.OBJECT_ID = o.OBJECT_ID
INNER JOIN sys.schemas s ON o.schema_id = s.schema_id
INNER JOIN (SELECT SUM(p.rows) TableRows, p.index_id, p.OBJECT_ID
FROM sys.partitions p GROUP BY p.index_id, p.OBJECT_ID) p
ON p.index_id = dm_ius.index_id AND dm_ius.OBJECT_ID = p.OBJECT_ID
WHERE OBJECTPROPERTY(dm_ius.OBJECT_ID,'IsUserTable') = 1
AND dm_ius.database_id = DB_ID()
AND i.type_desc = 'nonclustered'
AND i.is_primary_key = 0
AND i.is_unique_constraint = 0
ORDER BY (dm_ius.user_seeks + dm_ius.user_scans + dm_ius.user_lookups) ASC

http://blog.sqlauthority.com/2011/01/04/sql-server-2008-unused-index-script-download/


10

私は、Brent Ozar Unlimitedの無料の BlitzIndexスクリプト(Kendra Littleによって作成された)が、未使用のインデックス(および追加するのに有益なインデックス、他のインデックスの作業を複製しているインデックスなど)を分離する最良の方法であることを発見しました

http://www.brentozar.com/blitzindex/

統計カウントが最後にリセットされた(またはインデックスが作成/再作成された)以降にインデックスが読み取られた回数を示します。

私はブレントオザールがウェブキャストでよく読んだ経験則として、頻繁に読み込まれるテーブルのインデックスは10以下、静的/履歴/アーカイブされたデータで頻繁に変更されないテーブルのインデックスは20以上であると述べたようです。

それでもインポート速度に問題がある場合は、データベースがアクティブに照会されていないときがあります(おそらく、これは営業時間外です)。インデックスを削除し、データをインポートしてから、インデックスを再適用すると効果的です。(統計はもちろんリセットされます。)これは、各レコードが挿入されるとインデックスが更新され、ページが並べ替えられ、時間とディスクI / Oがかかるためです。にインデックスを作成するには、テーブルを1回スキャンする必要があります。

インデックスのタイプと関連するデータによっては、これを試してみる必要があるかもしれません。インデックスは、ニーズ/クエリが変化したときに定期的に確認する必要があります。


1
私はこのスクリプトを実行しましたが、それを解釈するための簡単なガイドがありましたら幸いです。
IrishChieftain

0

これを試して:

SELECT   OBJECT_NAME(S.[OBJECT_ID]) AS [OBJECT NAME], 
             I.[NAME] AS [INDEX NAME], 
             USER_SEEKS, 
             USER_SCANS, 
             USER_LOOKUPS, 
             USER_UPDATES 
    FROM     SYS.DM_DB_INDEX_USAGE_STATS AS S 
             INNER JOIN SYS.INDEXES AS I 
               ON I.[OBJECT_ID] = S.[OBJECT_ID] 
                  AND I.INDEX_ID = S.INDEX_ID 
    WHERE    OBJECTPROPERTY(S.[OBJECT_ID],'IsUserTable') = 1 

ラージ


0

最後に使用した日付とドロップするためのコードをRajのクエリに追加しました。

SELECT   OBJECT_NAME(S.[OBJECT_ID]) AS [OBJECT NAME], 
             I.[NAME] AS [INDEX NAME], type_desc,
             coalesce(last_user_seek,last_user_scan,last_user_lookup,last_system_scan,last_system_seek,last_system_lookup) as LastUsed,
             USER_SEEKS, 
             USER_SCANS, 
             USER_LOOKUPS, 
             USER_UPDATES ,
             last_user_seek,last_user_scan,last_user_lookup,last_system_scan,last_system_seek,last_system_lookup,
             'drop index ['+I.[NAME]+'] on ['+OBJECT_NAME(S.[OBJECT_ID])+'];' as DropStatement
    FROM     SYS.DM_DB_INDEX_USAGE_STATS AS S 
             INNER JOIN SYS.INDEXES AS I 
               ON I.[OBJECT_ID] = S.[OBJECT_ID] 
                  AND I.INDEX_ID = S.INDEX_ID 
    WHERE    OBJECTPROPERTY(S.[OBJECT_ID],'IsUserTable') = 1 
    order by type_desc,coalesce(last_user_seek,last_user_scan,last_user_lookup,last_system_scan,last_system_seek,last_system_lookup) desc
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.