Note: Before you create this procedure and start using it, make sure usp_SQLServerCarpenter_Tools_Estimate_Cardinality is created, ran, and the tbl_Cardinality table has data in it.
/* Author:Brahmanand Shukla (SQLServerCarpenter.com) Date:27-May-2022 Purpose:This procedure will list down all the indexes (Clustered as well Nonclustered Indexes) whose first key column having poor cardinality. The cardinality is accepted as an input to the procedure. Based on the input cardinality, the procedure fetches the indexes whose first key column having cardinality lower than what is supplied in the ascending order of their respective cardinality. If cardinality is not supplied: * The default input cardinality value is NULL; * It means fetch all the ineffctive indexes with Cardinality lower than 40 (this can be changed, if needed) in the ascending order of their cardinality value. Indexes may be an overhead if created on column(s) with poor cardinality. It is now up to you to decide which one makes sense, and which doesn’t. Take the decision accordingly and delete the ones that do not make sense. This procedure may be helpful in performance tuning assignments. Lower the value of cardinality means "Poor Cardinality" and indexes having such column as the first key column would be most likely an "Ineffective Index". Higher the value of cardinality means "Good Cardinality" and indexes having such column as the first key column would be most likely an "Effective index". Example: EXEC usp_SQLServerCarpenter_Tools_Estimate_Ineffective_Indexes EXEC usp_SQLServerCarpenter_Tools_Estimate_Ineffective_Indexes @Cardinality=100 *** Notes: *** Before you create this procedure and start using it, make sure usp_SQLServerCarpenter_Tools_Estimate_Cardinality is created, ran, and the tbl_Cardinality table has data in it. usp_SQLServerCarpenter_Tools_Estimate_Cardinality */CREATE OR ALTER PROCEDURE usp_SQLServerCarpenter_Tools_Estimate_Ineffective_Indexes ( @CardinalityTINYINT = NULL/*It can be any value between 0 to 100. Default is NULL */) AS BEGIN SET NOCOUNT ON; SELECT S.name AS [SchemaName] , T.name AS [TableName] , I.type_desc AS [IndexType] , I.name AS [IndexName] , C.name AS [ColumnName] , D.Cardinality , ROW_NUMBER() OVER(ORDER BY D.Cardinality ASC) AS [IneffectivenessRank] FROM sys.indexes I INNER JOIN sys.index_columns IC ON IC.object_id = I.object_id AND IC.index_id = I.index_id INNER JOIN sys.tables T ON T.object_id = I.object_id INNER JOIN sys.schemas S ON S.schema_id = T.schema_id INNER JOIN sys.columns C ON C.object_id = IC.object_id AND C.column_id = IC.column_id INNER JOIN tbl_Cardinality D ON D.ObjectID = T.object_id AND PARSENAME(D.ColumnName, 1) = C.name WHERE I.type_desc IN ('CLUSTERED', 'NONCLUSTERED') AND I.is_hypothetical = 0 AND IC.is_included_column = 0 AND IC.key_ordinal = 1 AND ((@Cardinality IS NULL AND D.Cardinality IS NOT NULL AND D.Cardinality < 40) OR (@Cardinality IS NOT NULL AND D.Cardinality IS NOT NULL AND D.Cardinality < @Cardinality)) END