Index stats with key,included columns, size - all you can eat
Use myDB GO THEN run script.
Either don't specify a table and get all results for the DB or specify table at top and get results for specific table.
Play around with Where clause conditions that I have provided, to get a feel of what it does.
****
This has helped me zero in on a problem with timeouts in about 2 minutes by identifying an index which had excessive pagelockwaits+rowlockwaits.
DECLARE @dbid INT,@tablename sysname --= 'schema.table' --''
SELECT @dbid = DB_ID()
SELECT sch.name+'.'+o.name TableName, COALESCE(i.name, 'HEAP') indexName,
COALESCE(IndexKey,'') IndexKey,S.partition_number PartNo, ps.used_page_count * 8/1024 AS IndexSizeMB,
COALESCE(CONVERT(SMALLDATETIME, STATS_DATE(S.object_id, i.index_id)),'') LastStatsUpDate, P.Rows as [rowcount],
(case when fill_factor =0 then 100 else fill_factor END) as [Fillfactor],i.index_id, i.is_unique,i.is_primary_key,
--Query Access
Usage.user_seeks seeks, Usage.user_scans scans, Usage.user_lookups lookups,range_scan_count,
singleton_lookup_count, Usage.user_scans *P.Rows as MaxRowsScanned ,
--Index Changes
S.nonleaf_update_count+s.leaf_update_count as updates, S.leaf_insert_count inserts,
S.leaf_delete_count deletes, S.nonleaf_delete_count nonleafdel,
--Rowlocks
row_lock_count RowLocks, row_lock_wait_count RwLkWtCnt,
cast(1.0 * row_lock_wait_in_ms / ( CASE WHEN row_lock_wait_count = 0 THEN 1 ELSE row_lock_wait_count END ) as numeric(10,2)) [Avg row lock time(ms)],
--PageLocks
page_lock_count,page_lock_wait_count PageLocks, page_lock_wait_in_ms ,
cast(1.0 *page_lock_wait_in_ms / ( CASE WHEN page_lock_wait_count = 0 THEN 1 ELSE page_lock_wait_count END ) as numeric(10,2)) [Avg pg lock time(ms)],
--PageLatchWaits
page_latch_wait_count,page_latch_wait_in_ms,
cast(1.0*page_latch_wait_in_ms / ( CASE WHEN page_latch_wait_count = 0 THEN 1 ELSE page_latch_wait_count END ) as numeric(10,2)) [Avg pg Latch time(ms)]
FROMsys.dm_db_index_operational_stats(@dbid, object_id(@tablename), NULL, NULL) S
INNER JOIN sys.partitions P on S.index_id = p.index_id AND s.object_id = p.object_id AND s.partition_number = p.partition_number
INNER JOIN sys.indexes i ON i.object_id = S.object_id AND i.index_id = S.index_id
INNER JOIN sys.objects o on i.object_id = o.object_id AND o.is_ms_shipped=0
INNER JOIN sys.schemas sch on o.schema_id = sch.schema_id
LEFT JOIN (
SELECT object_id, index_id, name, LEFT(subwindow.includeKey, LEN(subwindow.includeKey) - 1) AS 'IndexKey'
FROM ( SELECT i.index_id, i.name, object_id,
(SELECT c.name + ',' AS [text()]
FROMsys.indexes i2
INNER JOIN sys.index_columns ic ON ic.object_id = i2.object_id AND ic.index_id = i2.index_id
INNER JOIN sys.columns c ON c.object_id = ic.object_id AND c.column_id = ic.column_id
WHERE ic.is_included_column = 0 AND
i.object_id = i2.object_id AND
i.index_id = i2.index_id
ORDER BY i2.name
FOR XML PATH('') )
+ COALESCE(' INCLUDE:' +
(SELECTc.name + ',' AS [text()]
FROM sys.indexes i2
INNER JOIN sys.index_columns ic ON ic.object_id = i2.object_id AND
ic.index_id = i2.index_id
INNER JOIN sys.columns c ON c.object_id = ic.object_id AND
c.column_id = ic.column_id
WHERE ic.is_included_column = 1 AND
i.object_id = i2.object_id AND
i.index_id = i2.index_id
ORDER BY i2.name
FOR XML PATH('') ), '') AS includeKey
FROM sys.indexes i
) subwindow ) window ON window.object_id = i.object_id AND window.index_id = i.index_id
INNER JOIN sys.dm_db_index_usage_stats AS Usage ON i.object_id = Usage.object_id
AND i.index_id = Usage.index_id AND usage.database_id = S.database_id
INNER JOIN sys.dm_db_partition_stats PS on p.partition_id=ps.partition_id AND p.object_id = ps.object_id
AND p.index_id = ps.index_id AND p.partition_number = ps.partition_number
-------------------
WHERE s.database_id = @dbid AND sch.name+'.'+o.name = COALESCE(@tablename,sch.name+'.'+o.name)
--AND rows > 500000 AND user_seeks+user_scans =0 --Find large space wasters.
--AND row_lock_wait_count +page_lock_wait_count +page_latch_wait_count >0
---------order by
--ORDER BY 1 ASC,2,3,5 --alphabetically
--order by page_latch_wait_in_ms desc
order by RwLkWtCnt desc
--order by page_lock_wait_in_ms desc
--order by row_lock_wait_in_ms desc
--Order by case when user_seeks =0 then 0 else singleton_lookup_count/user_seeks END desc -- Potential Bad index seeks.
--order by MaxRowsScanned desc
--order by user_scans desc
--order by user_scans desc