· Uwe Janke
Commands / Get-sqmIndexUsageReport

Get-sqmIndexUsageReport

PerformancesqmSQLTool v1.9.169+ · New🔓 VIEW SERVER STATE + database access
Complements Get-sqmMissingIndexes (what is missing) and Get-sqmIndexFragmentation (state of what exists) with the question: which existing indexes cost more than they bring?

Unused: nonclustered, non-unique index without a single read since the last restart, but maintained on every write. Unique indexes and primary keys are never reported, they enforce rules.
Duplicate: same key columns, order, direction and filter as another index on the table. The clustered, primary key or unique index is kept; differing INCLUDE columns are named.
Overlapping: the key columns are the leading part of a wider index. The detail says whether the wider index already covers the INCLUDE columns.
Heap, Disabled and Hypothetical (Tuning Advisor leftovers) complete the picture.

The function never changes an index. DROP suggestions are written to _DropCandidates.sql, every line commented out. Usage counters start at zero after each restart or failover: with less than -MinUptimeDays of uptime it warns and marks Unused as unreliable. An index used only by the month-end run looks unused for weeks, so check with the application owner first.

Parameters

ParameterTypeRequiredDefaultNotes
-SqlInstancestringOptional$env:COMPUTERNAMETarget SQL Server instance.
-SqlCredentialPSCredentialOptional, SQL or Windows credential.
-Databasestring[]Optionalall user DBsDatabase names, wildcards allowed. ReportServer, SSISDB and distribution only when named explicitly.
-Findingstring[]OptionalallUnused, Duplicate, Overlapping, Heap, Disabled, Hypothetical.
-MinUptimeDaysintOptional7Below this uptime Unused is flagged as unreliable and a warning is written.
-MinSizeMBdoubleOptional0Ignore smaller indexes and heaps.
-OutputPathstringOptional<config>\IndexUsageReportDirectory for CSV, HTML and the commented DROP script.
-NoReportswitchSwitch$falseDo not write CSV/HTML, only return objects.
-NoOpenswitchSwitch$falseDo not open the HTML report after creation.
-EnableExceptionswitchSwitch$falseThrow exceptions immediately instead of Write-Error.

Execution Flow

START Instance uptime from sys.dm_os_sys_info below -MinUptimeDays: warning, Unused marked unreliable Per database: all indexes with keys, includes, usage and size sys.indexes, index_columns, dm_db_index_usage_stats, dm_db_partition_stats Per table: compare indexes duplicates first (keep clustered / PK / unique), then prefix overlaps never Unused for unique indexes or primary keys CSV + HTML + _DropCandidates.sql every DROP statement commented out, nothing is executed DONE

Return Value

PSCustomObject per finding: DatabaseName, SchemaName, TableName, IndexName, IndexType, Finding, Detail, RelatedIndex, KeyColumns, IncludeColumns, Filter, Reads, Writes, LastUserRead, Rows, SizeMB, UptimeDays, DropStatement.

Examples

All findings in all user databases
Get-sqmIndexUsageReport -SqlInstance "SQL01"
Only duplicates and overlaps in the shop databases
Get-sqmIndexUsageReport -SqlInstance "SQL01" -Database "Shop*" -Finding Duplicate, Overlapping
Large unused indexes as a list
Get-sqmIndexUsageReport -SqlInstance "SQL01" -Finding Unused -MinSizeMB 500 -NoReport |
    Sort-Object SizeMB -Descending | Format-Table DatabaseName, TableName, IndexName, SizeMB, Writes