/* Server: ssunb008vm01.sunstore.ch Format: GCM Business: TPPHAR type: DEVE Version: 23.1.10016.00066 01.11.2022, TSC */ USE Arizona; BEGIN TRANSACTION; SET XACT_ABORT ON; SET NOCOUNT ON; IF OBJECT_ID('tempdb..#chkRes') IS NOT NULL BEGIN; DROP TABLE #chkRes; END DECLARE @ref_schema VARCHAR(50) = 'dbo'; DECLARE @ref_table VARCHAR(100) = 'entry'; CREATE TABLE #chkRes ( tbl_name NVARCHAR(128) NOT NULL ,[schema_name] VARCHAR(50) NOT NULL ,[type] CHAR(2) NULL ,index_name NVARCHAR(128) NULL ,[index_id] INT NOT NULL ,[Reads] BIGINT NOT NULL ,[Writes] BIGINT NOT NULL ,[delta] BIGINT NOT NULL ,[index_type] NVARCHAR(60) NULL ,[FillFactor] TINYINT NULL ,[has_filter] BIT NOT NULL ,[filter_definition] NVARCHAR(MAX) NULL ,[last_user_scan] DATETIME NULL ,[last_user_lookup] DATETIME NULL ,[last_user_seek] DATETIME NULL ,[IndexColumns] NVARCHAR(MAX) NULL ,[IncludedColumns] NVARCHAR(MAX) NULL ,[primary_table] NVARCHAR(500) NULL ,[pk_column_name] NVARCHAR(128) NULL ,[fk_constraint_name] NVARCHAR(128) NULL ,comp_drop_cmd AS 'DROP INDEX ' + index_name + ' ON ' + [schema_name] + '.' + tbl_name + ';' ); ;WITH ColInfo AS ( SELECT o.name AS TblName ,s.name + '.' + o.name AS SchemaTbl ,i.name AS IndexName ,i.is_primary_key AS IsPrimaryKey ,i.is_unique_constraint AS IsUniqueConstraint ,i.is_unique AS IsUnique ,c.name AS ColName ,c.is_computed AS IsComputedCol ,ic.is_included_column AS IsIncludedCol ,ic.key_ordinal ,i.filter_definition AS FilterDefinition FROM sys.objects o INNER JOIN sys.schemas s ON o.schema_id = s.schema_id INNER JOIN sys.columns c ON o.object_id = c.object_id INNER JOIN sys.indexes i ON c.object_id = i.object_id INNER JOIN sys.index_columns ic ON i.index_id = ic.index_id AND o.object_id = ic.object_id AND c.column_id = ic.column_id ) --- Index Read/Write stats (all tables in current DB) ordered by Reads (Query 62) (Overall Index Usage - Reads) INSERT INTO #chkRes ( tbl_name ,[schema_name] ,[type] ,index_name ,index_id ,Reads ,Writes ,delta ,index_type ,[FillFactor] ,has_filter ,filter_definition ,last_user_scan ,last_user_lookup ,last_user_seek ,IndexColumns ,IncludedColumns ,primary_table ,pk_column_name ,fk_constraint_name ) SELECT o.name AS [tbl_Name] ,SCHEMA_NAME(o.schema_id) AS [schema_name] ,o.type ,i.name AS [index_name] ,i.index_id ,user_seeks + user_scans + user_lookups AS [Reads] ,s.user_updates AS [Writes] ,CASE WHEN s.user_updates > user_seeks + user_scans + user_lookups THEN s.user_updates - (user_seeks + user_scans + user_lookups) ELSE (user_seeks + user_scans + user_lookups) - s.user_updates END AS delta ,i.type_desc AS [index_type] ,i.fill_factor AS [fill_factor] ,i.has_filter ,i.filter_definition ,s.last_user_scan ,s.last_user_lookup ,s.last_user_seek ,idx_cols.IndexColumns ,idx_cols.IncludedColumns ,fk.primary_table ,fk.pk_column_name ,fk.fk_constraint_name FROM sys.dm_db_index_usage_stats AS s WITH (NOLOCK) INNER JOIN sys.indexes AS i WITH (NOLOCK) ON s.object_id = i.object_id INNER JOIN sys.objects o WITH (NOLOCK) ON s.object_id = o.object_id OUTER APPLY ( SELECT DISTINCT x.TblName ,x.IndexName ,x.IsPrimaryKey ,x.IsUniqueConstraint ,x.IsUnique --,size.IndexSizeKB ,c.IndexColumns ,ci.IncludedColumns ,cc.ComputedColumns ,x.FilterDefinition FROM ColInfo x CROSS APPLY ( SELECT STUFF(sq.strXML, 1, 2, '') AS IndexColumns FROM ( SELECT ', ' + ISNULL(x2.ColName, '') FROM ColInfo x2 WHERE x.TblName = x2.TblName AND x.IndexName = x2.IndexName AND x2.IsIncludedCol = 0 ORDER BY x2.key_ordinal FOR XML PATH('') ) sq(strXML) ) c OUTER APPLY ( SELECT STUFF(sq.strXML, 1, 2, '') AS IncludedColumns FROM ( SELECT ', ' + ISNULL(x2.ColName, '') FROM ColInfo x2 WHERE x.TblName = x2.TblName AND x.IndexName = x2.IndexName AND x2.IsIncludedCol = 1 ORDER BY x2.key_ordinal FOR XML PATH('') ) sq(strXML) ) ci OUTER APPLY ( SELECT STUFF(sq.strXML, 1, 2, '') AS ComputedColumns FROM ( SELECT ', ' + ISNULL(x2.ColName, '') FROM ColInfo x2 WHERE x.TblName = x2.TblName AND x.IndexName = x2.IndexName AND x2.IsComputedCol = 1 ORDER BY x2.key_ordinal FOR XML PATH('') ) sq(strXML) ) cc WHERE x.TblName = o.name AND x.IndexName = i.name ) idx_cols LEFT OUTER JOIN ( SELECT SCHEMA_NAME(tab.schema_id) + '.' + tab.name AS [table] ,col.column_id ,col.name AS column_name ,CASE WHEN fk.object_id IS NOT NULL THEN '>-' ELSE NULL END AS rel ,SCHEMA_NAME(pk_tab.schema_id) + '.' + pk_tab.name AS primary_table ,pk_col.name AS pk_column_name ,fk_cols.constraint_column_id AS NO ,fk.name AS fk_constraint_name ,tab.name AS tbl_name FROM sys.tables tab INNER JOIN sys.columns col ON col.object_id = tab.object_id LEFT OUTER JOIN sys.foreign_key_columns fk_cols ON fk_cols.parent_object_id = tab.object_id AND fk_cols.parent_column_id = col.column_id LEFT OUTER JOIN sys.foreign_keys fk ON fk.object_id = fk_cols.constraint_object_id LEFT OUTER JOIN sys.tables pk_tab ON pk_tab.object_id = fk_cols.referenced_object_id LEFT OUTER JOIN sys.columns pk_col ON pk_col.column_id = fk_cols.referenced_column_id AND pk_col.object_id = fk_cols.referenced_object_id WHERE fk.object_id IS NOT NULL ) fk ON fk.tbl_name = o.name AND idx_cols.IndexColumns LIKE '%' + fk.column_name + '%' WHERE o.type = 'U' -- user table AND i.index_id = s.index_id AND s.database_id = DB_ID() AND o.name = @ref_table AND SCHEMA_NAME(o.schema_id) = @ref_schema ORDER BY delta DESC --ORDER BY user_seeks + user_scans + user_lookups DESC -- Order by reads --ORDER BY s.user_updates DESC OPTION -- Order by writes OPTION (RECOMPILE); /* list back data */ SELECT cr.tbl_name ,cr.[schema_name] ,cr.[type] ,cr.index_name ,cr.index_id ,cr.Reads ,cr.Writes ,cr.delta ,cr.index_type ,cr.[FillFactor] ,cr.has_filter ,cr.filter_definition ,cr.last_user_scan ,cr.last_user_lookup ,cr.last_user_seek ,cr.IndexColumns ,cr.IncludedColumns ,cr.primary_table ,cr.pk_column_name ,cr.fk_constraint_name FROM #chkRes cr ORDER BY IndexColumns ; ROLLBACK TRANSACTION RETURN --/* Check if index with FK are in the list, alert if it's the case */ --IF EXISTS( -- SELECT 1 -- FROM #chkRes cr -- WHERE cr.Reads = 0 --not used -- AND cr.Writes > 100 --but maintained -- AND cr.fk_constraint_name IS NOT NULL --is part of a FK --) BEGIN -- SELECT -- 'This index is tied to a column part of a FK, check if dropping is to be done.' AS msg -- ,cr.[schema_name] -- ,cr.tbl_name -- ,cr.index_name -- ,cr.Reads -- ,cr.Writes -- ,cr.primary_table -- ,cr.pk_column_name -- ,cr.fk_constraint_name -- FROM #chkRes cr -- WHERE cr.Reads = 0 --not used -- AND cr.Writes > 100 --but maintained -- AND cr.fk_constraint_name IS NOT NULL --is part of a FK -- AND cr.index_type = 'NONCLUSTERED' --END --/* declare variables */ --DECLARE -- @table_name VARCHAR(MAX) -- ,@schema_name VARCHAR(20) -- ,@index_name VARCHAR(500) -- ,@drop_cmd VARCHAR(MAX) -- ; --DECLARE dropIdx CURSOR LOCAL FORWARD_ONLY FAST_FORWARD READ_ONLY FOR -- SELECT -- cr.tbl_name -- ,cr.[schema_name] -- ,cr.index_name -- ,cr.comp_drop_cmd -- FROM #chkRes cr -- WHERE cr.Reads = 0 --not used on select -- AND cr.Writes > 100 --but maintained on insert / update -- AND cr.fk_constraint_name IS NULL --not part of a FK -- AND cr.index_type = 'NONCLUSTERED' --ignore clustered & heaps -- ; --OPEN dropIdx; --FETCH NEXT FROM dropIdx --INTO -- @table_name -- ,@schema_name -- ,@index_name -- ,@drop_cmd -- ; --WHILE @@FETCH_STATUS = 0 BEGIN -- PRINT @drop_cmd;--'Dropping index ' + @index_name + ' on ' + @schema_name + '.' + @table_name; -- --EXEC(@drop_cmd); -- FETCH NEXT FROM dropIdx -- INTO -- @table_name -- ,@schema_name -- ,@index_name -- ,@drop_cmd -- ; --END --CLOSE dropIdx; --DEALLOCATE dropIdx; --SELECT cr.tbl_name -- ,cr.[schema_name] -- ,cr.index_name -- ,cr.Reads -- ,cr.Writes -- ,cr.delta -- ,cr.index_type -- ,cr.last_user_scan -- ,cr.last_user_lookup -- ,cr.last_user_seek -- ,cr.IndexColumns -- ,cr.IncludedColumns -- ,cr.primary_table -- ,cr.pk_column_name -- ,cr.fk_constraint_name --FROM #chkRes cr --ORDER BY cr.delta DESC --; --ROLLBACK TRANSACTION;