Blog Post

With A Little Bit of Care, You Can Use the DMVs to Auto-Create Some Missing Indexes, Here Is How (but with Caveats)

,

<b>An Automagic Index Creation Script? No, but a start to deal with Missing Indexes</b>

Here's the useful join from a number of Index related DMVs - it grabs the top 50 possible missing indexes ordered by priority

select top 50 priority = avg_total_user_cost * avg_user_impact *(user_seeks + user_scans)

,d.statement

,d.equality_columns

,d.inequality_columns

,d.included_columns

,s.avg_total_user_cost

,s.avg_user_impact

,s.user_seeks, s.user_scans

from sys.dm_db_missing_index_group_stats s

join sys.dm_db_missing_index_groups g

on s.group_handle=g.index_group_handle

join sys.dm_db_missing_index_details d

on g.index_handle = d.index_handle

where s.user_seeks > 3000

order by priority desc

--Below integrated Above and adding the Create Index Missing_ concatenated...tweak to your respective system (note the obvious Missing Label to them, makes it easy to drop them for upgrades, since the SCOM product group will not support these, you are at your own risk)


SELECT 'CREATE INDEX missing_index_' + CONVERT (varchar, a.index_group_handle) + '_' + CONVERT (varchar, c.index_handle) + ' ON ' + c.statement + ' (' + ISNULL (c.equality_columns,'') + CASE WHEN c.equality_columns IS NOT NULL AND c.inequality_columns IS NOT NULL THEN ',' ELSE '' END + ISNULL (c.inequality_columns, '') + ')' + ISNULL (' INCLUDE (' + c.included_columns + ')', '') AS create_index_statement ,CONVERT (DECIMAL (28,1), b.avg_total_user_cost * b.avg_user_impact * (b.user_seeks + b.user_scans) ) AS improvement_measurement, b.unique_compiles, b.user_seeks, b.user_scans, avg_user_impact, avg_system_impact, last_user_seek, last_user_scan

FROM sys.dm_db_missing_index_groups a

 INNER JOIN sys.dm_db_missing_index_group_stats b

   ON b.group_handle = a.index_group_handle

   INNER JOIN sys.dm_db_missing_index_details c

    ON a.index_handle = c.index_handle

WHERE b.avg_user_impact > 50
-- originally 90 (MVP Kevin E. Kline's suggestion), but I dropped this to 30 to see
-- but on larger databases I changed it to 50

AND c.database_id = DB_ID()

AND b.user_seeks > 30
-- modify this as necessary, for a DW, I would do it as low as 30, for other systems,
-- I went as high as 3000 (caveat - test and check on your systems thoroughly!)

ORDER BY b.avg_total_user_cost * b.avg_user_impact * (b.user_seeks + b.user_scans) DESC

--- created on SCOM's OperationsManager (for example, not because DBAs have issues with SCOM... 🙂

Remember not to add too many indexes to tables that have many already, ESPECIALLY if that table will continue to have significant Inserts

The addition of these 'missing indexes' will improve performance for READ operations on the tables

A LOUD THANK YOU to Mohit Gupta, a Canadian SQL Premier Field Engineer, for collaboration on the following 🙂

USE [OperationsManager]

GO

CREATE INDEX missing_index_1820_1819 ON [OperationsManager].[dbo].[Relationship] ([LastModified]) INCLUDE ([RelationshipId], [SourceEntityId], [TargetEntityId], [RelationshipTypeId], [IsDeleted])

-- double check what was there already:

CREATE NONCLUSTERED INDEX [idx_BaseManagedEntity_TopLevelHostEntityId] ON [dbo].[BaseManagedEntity]

(

        [BaseManagedEntityId] ASC,

        [TopLevelHostEntityId] ASC

)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, IGNORE_DUP_KEY = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON, FILLFACTOR = 80) ON [PRIMARY]

GO

-- fine, np

CREATE INDEX missing_index_55_54 ON [OperationsManager].[dbo].[BaseManagedEntity] ([BaseManagedTypeId], [IsDeleted]) INCLUDE ([BaseManagedEntityId], [DisplayName])

CREATE INDEX missing_index_24_23 ON [OperationsManager].[dbo].[Relationship] ([LastModified]) INCLUDE ([RelationshipId], [SourceEntityId], [TargetEntityId], [RelationshipTypeId], [IsDeleted], [TimeAdded])

-- double check what was there already:

USE [OperationsManager]

GO

ALTER TABLE [dbo].[TypedManagedEntity] ADD CONSTRAINT [idx_ManagedEntityManagedTypeId] UNIQUE NONCLUSTERED

(

        [BaseManagedEntityId] ASC,

        [ManagedTypeId] ASC

)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, IGNORE_DUP_KEY = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON, FILLFACTOR = 80) ON [PRIMARY]

GO

CREATE INDEX missing_index_1830_1829 ON [OperationsManager].[dbo].[TypedManagedEntity] ([LastModified]) INCLUDE ([BaseManagedEntityId], [ManagedTypeId], [IsDeleted])

CREATE INDEX missing_index_1604_1603 ON [OperationsManager].[dbo].[Monitor] ([TargetManagedEntityType]) INCLUDE ([MonitorId], [ParentMonitorId], [IsDependencyMonitor], [MonitorName], [RelationshipTypeId], [MemberMonitorId])

CREATE INDEX missing_index_1460_1459 ON [OperationsManager].[dbo].[Report] ([ReportTarget])

CREATE INDEX missing_index_1452_1451 ON [OperationsManager].[dbo].[Views] ([ViewTypeId]) INCLUDE ([ViewId])

CREATE INDEX missing_index_117_116 ON [OperationsManager].[dbo].[Report] ([ManagementPackId])

--- then had to drop missing_index_1820_1819 because it was a mistake (I also learned along the way to NAME the MISSING indexes added Better, see below

-- Only a clustered index can be dropped online btw 🙂

USE [OperationsManager]

GO

DROP INDEX [missing_index_1820_1819] ON [dbo].[Relationship] WITH ( ONLINE = OFF )

GO

--- For OperationsManagerDW

USE [OperationsManagerDW]

GO

/****** Object: Index [UN_RelationshipManagementGroup_RelationshipRowIdFromDateTime] Script Date: 11/30/2011 15:56:35 ******/

ALTER TABLE [dbo].[RelationshipManagementGroup] ADD CONSTRAINT [UN_RelationshipManagementGroup_RelationshipRowIdFromDateTime] UNIQUE NONCLUSTERED

(

        [RelationshipRowId] ASC,

        [FromDateTime] ASC

)

INCLUDE ([ToDateTime]),

WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, IGNORE_DUP_KEY = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON, FILLFACTOR = 100) ON [PRIMARY]

CREATE INDEX missing_index_3655_3654 ON [OperationsManagerDW].[dbo].[RelationshipManagementGroup] ([FromDateTime]) INCLUDE ([RelationshipRowId], [ToDateTime])

-- do not create, already existing

USE [OperationsManagerDW]

GO

/****** Object: Index [IDX_MaintenanceMode_ManagedEntityRowIdStartDateTime] Script Date: 12/01/2011 17:30:02 ******/

CREATE UNIQUE NONCLUSTERED INDEX [IDX_MaintenanceMode_ManagedEntityRowIdStartDateTime] ON [dbo].[MaintenanceMode]

(

        [ManagedEntityRowId] ASC,

        [StartDateTime] ASC

)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, IGNORE_DUP_KEY = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON, FILLFACTOR = 100) ON [PRIMARY]

GO

USE [OperationsManagerDW]

GO

/****** Object: Index [PK_MaintenanceMode] Script Date: 12/01/2011 17:30:25 ******/

ALTER TABLE [dbo].[MaintenanceMode] ADD CONSTRAINT [PK_MaintenanceMode] PRIMARY KEY CLUSTERED

(

        [MaintenanceModeRowId] ASC

)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, IGNORE_DUP_KEY = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON, FILLFACTOR = 100) ON [PRIMARY]

GO

-- no related indexes, so created.

CREATE INDEX missing_index_136_135 ON [OperationsManagerDW].[dbo].[MaintenanceMode] ([StartDateTime]) INCLUDE ([ManagedEntityRowId], [EndDateTime], [PlannedMaintenanceInd])

--

USE [OperationsManagerDW]

GO

ALTER TABLE [dbo].[ManagedEntityType] ADD CONSTRAINT [PK_ManagedEntityType] PRIMARY KEY CLUSTERED

(

        [ManagedEntityTypeRowId] ASC

)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, IGNORE_DUP_KEY = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON, FILLFACTOR = 100) ON [PRIMARY]

GO

ALTER TABLE [dbo].[ManagedEntityType] ADD CONSTRAINT [UN_ManagedEntityType_ManagedEntityTypeGuid] UNIQUE NONCLUSTERED

(

        [ManagedEntityTypeGuid] ASC

)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, IGNORE_DUP_KEY = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON, FILLFACTOR = 100) ON [PRIMARY]

GO

-- no related indexes, so created.

CREATE INDEX missing_index_1848_1847 ON [OperationsManagerDW].[dbo].[ManagedEntityType] ([ManagedEntityTypeSystemName])

-- check existing

USE [OperationsManagerDW]

GO

/****** Object: Index [IX_AlertStage_AlertGuidDBLastModifiedDateTimeResolutionStateAlertStageRowId] Script Date: 12/01/2011 17:33:17 ******/

CREATE NONCLUSTERED INDEX [IX_AlertStage_AlertGuidDBLastModifiedDateTimeResolutionStateAlertStageRowId] ON [Alert].[AlertStage]

(

        [AlertGuid] ASC,

        [DBLastModifiedDateTime] ASC,

        [ResolutionState] ASC,

        [AlertStageRowId] ASC

)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, IGNORE_DUP_KEY = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON, FILLFACTOR = 100) ON [PRIMARY]

GO

-- tiny table, not worth it.

CREATE INDEX missing_index_1860_1859 ON [OperationsManagerDW].[Alert].[AlertStage] ([MonitorAlertInd], [WorkflowRowId])

CREATE INDEX missing_index_1929_1928 ON [OperationsManagerDW].[Alert].[AlertStage] ([AlertRowId])

CREATE INDEX missing_index_1880_1879 ON [OperationsManagerDW].[Alert].[AlertStage] ([AlertRowId]) INCLUDE ([RaisedDateTime])

-- - smaller table, checking anyway

USE [OperationsManagerDW]

GO

CREATE NONCLUSTERED INDEX [IX_MonitorManagementPackVersion_ManagementPackVersionRowId] ON [dbo].[MonitorManagementPackVersion]

(

        [ManagementPackVersionRowId] ASC

)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, IGNORE_DUP_KEY = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON, FILLFACTOR = 100) ON [PRIMARY]

GO

-- did not bother

CREATE INDEX missing_index_1834_1833 ON [OperationsManagerDW].[dbo].[MonitorManagementPackVersion] ([RelationshipTypeRowId])

-- check current indexes on that table for overlap, size is 49k rows, so worth it for size

USE [OperationsManagerDW]

GO

CREATE NONCLUSTERED INDEX [IX_EventCategory_LastReceivedDateTime] ON [dbo].[EventCategory]

(

        [LastReceivedDateTime] ASC

)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, IGNORE_DUP_KEY = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON, FILLFACTOR = 100) ON [PRIMARY]

USE [OperationsManagerDW]

GO

ALTER TABLE [dbo].[EventCategory] ADD CONSTRAINT [PK_EventCategory] PRIMARY KEY CLUSTERED

(

        [EventCategoryRowId] ASC

)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, IGNORE_DUP_KEY = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON, FILLFACTOR = 100) ON [PRIMARY]

GO

--created because it was usefull

CREATE INDEX missing_index_2_EventCategoryID_LastRecDateTime ON [OperationsManagerDW].[dbo].[EventCategory] ([EventCategoryId],[LastReceivedDateTime]) INCLUDE ([EventCategoryRowId], [EventPublisherRowId])

--check existing and table size (1000 rows, not worth it, but did it anyway)

CREATE INDEX missing_index_131_RelationshipTypeSystemName ON [OperationsManagerDW].[dbo].[RelationshipType] ([RelationshipTypeSystemName])

-- 2k in table, and none of the current covering

USE [OperationsManagerDW]

GO

CREATE NONCLUSTERED INDEX [IX_DiscoveryManagementPackVersion_ManagementPackVersionRowId] ON [dbo].[DiscoveryManagementPackVersion]

(

        [ManagementPackVersionRowId] ASC

)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, IGNORE_DUP_KEY = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON, FILLFACTOR = 100) ON [PRIMARY]

GO

ALTER TABLE [dbo].[DiscoveryManagementPackVersion] ADD CONSTRAINT [PK_DiscoveryManagementPackVersion] PRIMARY KEY CLUSTERED

(

        [DiscoveryManagementPackVersionRowId] ASC

)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, IGNORE_DUP_KEY = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON, FILLFACTOR = 100) ON [PRIMARY]

GO

USE [OperationsManagerDW]

GO

ALTER TABLE [dbo].[DiscoveryManagementPackVersion] ADD CONSTRAINT [UN_DiscoveryManagementPackVersion_DiscoveryManagementPack] UNIQUE NONCLUSTERED

(

        [DiscoveryRowId] ASC,

        [ManagementPackVersionRowId] ASC

)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, IGNORE_DUP_KEY = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON, FILLFACTOR = 100) ON [PRIMARY]

GO

-- created because worth it.

CREATE INDEX missing_index_WorkflowCategoryRowId ON [OperationsManagerDW].[dbo].[DiscoveryManagementPackVersion] ([WorkflowCategoryRowId])

-- Alert Stage has barely any rows, so moving on...

CREATE INDEX missing_index_28205_28204 ON [OperationsManagerDW].[Alert].[AlertStage] ([InsertReadyInd]) INCLUDE ([DatasetId], [ManagementGroupGuid], [AlertGuid], [AlertProblemGuid], [ManagedEntityGuid], [AlertName], [AlertDescription], [Severity], [Priority], [Category], [MonitorAlertInd], [WorkflowGuid], [RaisedDateTime], [CreatedDateTime], [ResolutionState], [Owner], [TicketId], [CustomField1], [CustomField2], [CustomField3], [CustomField4], [CustomField5], [CustomField6], [CustomField7], [CustomField8], [CustomField9], [CustomField10], [SiteName], [AlertParams], [ParameterHash], [RepeatCount], [AlertStringGuid], [DBLastModifiedDateTime], [DBLastModifiedByUserId], [AlertStageRowId], [AlertRowId], [TableGuid], [ManagedEntityRowId], [WorkflowRowId], [DWCreatedDateTime])

-- ditto this one is NOT worth creating either, SO MORAL OF THE STORY EVALUATE EACH ONE...

CREATE INDEX missing_index_1878_1877 ON [OperationsManagerDW].[Alert].[AlertStage] ([AlertRowId],[RaisedDateTime])

--- as a post validation, check through Jacob Buter's script as mentioned on Paul Neilsen's collaboration

--with fellow heavey-weight Itzik Ben-Gan

--- this will make sure you have not added Duplicate indexes 🙂 although they could have existed already

SET NOCOUNT ON

DECLARE @objname nvarchar(776)

     , @objid int -- the object id of the table

     ,@indid smallint -- the index id of an index

     , @groupid smallint -- the filegroup id of an index

     , @indname sysname

     , @groupname sysname

     , @status int

     , @keys nvarchar(2126) --Length (16*max_identifierLength)+(15*2)+(16*3)

     , @dbname sysname

     , @usrname sysname

     , @i int

     , @thiskey nvarchar(131) -- 128+3

-- Check to see that the object names are local to the current database.

SELECT @dbname = parsename(@objname,3)

IF @dbname IS NOT NULL

AND @dbname <> db_name()

BEGIN

 raiserror(15250,-1,-1)

END

-- create temp table

create table #indextable

(usr_name sysname

,table_name sysname

,index_name sysname collate database_default

,stats int

,groupname sysname collate database_default

,index_keys nvarchar(2126) collate database_default -- see @keys above for length descr

)

-- OPEN CURSOR OVER TABLES

DECLARE cur_tables CURSOR LOCAL STATIC

FOR

 SELECT t1.id

      , t1.name

      , t2.name

   FROM sysobjects t1

  INNER JOIN sysusers t2 on t1.uid = t2.uid

  WHERE type = 'U'

OPEN cur_tables

FETCH cur_tables

INTO @objid

   , @objname

   , @usrname

WHILE @@fetch_status >= 0

BEGIN

-- OPEN CURSOR OVER INDEXES

 DECLARE cur_indexes CURSOR LOCAL STATIC

 FOR

   SELECT indid

        , groupid

        , name

        , status

     FROM sysindexes

    WHERE id = @objid

      AND indid > 0

      AND indid < 255

      AND (status & 64) = 0

    ORDER BY indid

 OPEN cur_indexes

 FETCH cur_indexes

  INTO @indid

     , @groupid

     , @indname

     , @status

 WHILE @@fetch_status >= 0

 BEGIN

   -- First we'll figure out what the keys are.

   SELECT @keys = index_col(@usrname + '.' + @objname, @indid, 1)

        , @i = 2

   IF (indexkey_property(@objid, @indid, 1, 'isdescending') = 1)

     SELECT @keys = @keys

                  + '(-)'

   SELECT @thiskey = index_col(@usrname + '.' + @objname, @indid, @i)

   IF ((@thiskey IS NOT NULL)

   AND (indexkey_property(@objid, @indid, @i, 'isdescending') = 1))

     SELECT @thiskey = @thiskey

                     + '(-)'

   WHILE (@thiskey IS NOT NULL)

   BEGIN

     SELECT @keys = @keys

                  + ', '

                  + @thiskey

          , @i = @i + 1

     SELECT @thiskey = index_col(@usrname + '.' + @objname, @indid, @i)

     IF ((@thiskey IS NOT NULL)

     AND (indexkey_property(@objid, @indid, @i, 'isdescending') = 1))

       SELECT @thiskey = @thiskey + '(-)'

   END

   SELECT @groupname = groupname

     FROM sysfilegroups

    WHERE groupid = @groupid

   -- INSERT ROW FOR INDEX

   INSERT INTO #indextable

          VALUES (@usrname, @objname, @indname, @status, @groupname, @keys)

   -- Next index

   FETCH cur_indexes

    INTO @indid

       , @groupid

       , @indname

       , @status

 END

 CLOSE cur_indexes

 DEALLOCATE cur_indexes

 FETCH cur_tables

  INTO @objid

     , @objname

     , @usrname

END

DEALLOCATE cur_tables

-- DISPLAY THE RESULTS DUPLICATED

SELECT @@SERVERNAME as Instance

    , DB_NAME() as DatabaseName

    , t1.usr_name as usr_name

    , t1.table_name as table_name

    , t1.index_name as index_name

    , convert(varchar(210), --bits 16 off, 1, 2, 16777216 on, located on group

              case

                when (t1.stats & 16)<>0

                  then 'clustered'

                  else 'nonclustered'

              end

            + case

                when (t1.stats & 1)<>0

                  then ', ignore duplicate keys'

                  else ''

              end

            + case

                when (t1.stats & 2)<>0

                  then ', unique'

                  else ''

              end

            + case

                when (t1.stats & 4)<>0

                  then ', ignore duplicate rows'

                  else ''

              end

            + case

                when (t1.stats & 64)<>0

                  then ', statistics'

                  else

                    case

                      when (t1.stats & 32)<>0

                        then ', hypothetical'

                        else ''

                    end

              end

            + case

                when (t1.stats & 2048)<>0

                  then ', primary_key'

                  else ''

              end

            + case

                when (t1.stats & 4096)<>0

                  then ', unique_key'

                  else ''

              end

           + case

               when (t1.stats & 8388608)<>0

                 then ', auto_create'

                 else ''

             end

           + case

               when (t1.stats & 16777216)<>0

                 then ', stats_no_recompute'

                 else ''

               end

           + ' located on '

           + t1.groupname) as index_description

    , t2.index_keys as index_keys

    , t2.index_name as index_name

    , convert(varchar(210), --bits 16 off, 1, 2, 16777216 on, located on group

              case

                when (t2.stats & 16)<>0

                  then 'clustered'

                  else 'nonclustered'

              end

            + case

                when (t2.stats & 1)<>0

                  then ', ignore duplicate keys'

                  else ''

              end

            + case

                when (t2.stats & 2)<>0

                  then ', unique'

                  else ''

              end

            + case

                when (t2.stats & 4)<>0

                  then ', ignore duplicate rows'

                  else ''

              end

            + case

                when (t2.stats & 64)<>0

                  then ', statistics'

                  else

                    case

                      when (t2.stats & 32)<>0

                        then ', hypothetical'

                        else ''

                    end

              end

            + case

                when (t2.stats & 2048)<>0

                  then ', primary_key'

                  else ''

              end

            + case

                when (t2.stats & 4096)<>0

                  then ', unique key'

                  else ''

              end

            + case

                when (t2.stats & 8388608)<>0

                  then ', auto create'

                  else ''

                end

            + case

                when (t2.stats & 16777216)<>0

                  then ', stats no recompute'

                  else ''

              end

            + ' located on '

            + t2.groupname) as index_description

    , t2.index_keys as index_keys

 FROM #indextable t1

INNER JOIN #indextable t2 ON t1.table_name = t2.table_name

                         AND t1.index_name != t2.index_name

                         AND t1.index_keys = t2.index_keys

ORDER BY t1.table_name

       , t1.index_name

-- DISPLAY THE RESULTS OVERLAPPING

SELECT @@SERVERNAME as Instance

    , DB_NAME() as DatabaseName

    , t1.usr_name as usr_name

    , t1.table_name as table_name

    , t1.index_name as index_name

    , convert(varchar(210), --bits 16 off, 1, 2, 16777216 on, located on group

              case

                when (t1.stats & 16)<>0

                  then 'clustered'

                  else 'nonclustered'

              end

            + case

                when (t1.stats & 1)<>0

                  then ', ignore duplicate keys'

                  else ''

              end

            + case

                when (t1.stats & 2)<>0

                  then ', unique'

                  else ''

              end

            + case

                when (t1.stats & 4)<>0

                  then ', ignore duplicate rows'

                  else ''

              end

            + case

                when (t1.stats & 64)<>0

                  then ', statistics'

                  else

                    case

                      when (t1.stats & 32)<>0

                        then ', hypothetical'

                        else ''

                    end

              end

            + case

                when (t1.stats & 2048)<>0

                  then ', primary_key'

                  else ''

              end

            + case

                when (t1.stats & 4096)<>0

                  then ', unique key'

                  else ''

              end

           + case

               when (t1.stats & 8388608)<>0

                 then ', auto create'

                 else ''

             end

           + case

               when (t1.stats & 16777216)<>0

                 then 'stats no recompute'

                 else ''

               end

           + ' located on '

           + t1.groupname) as index_description

    , t2.index_keys as index_keys

    , t2.index_name as index_name

    , convert(varchar(210), --bits 16 off, 1, 2, 16777216 on, located on group

              case

                when (t2.stats & 16)<>0

                  then 'clustered'

                  else 'nonclustered'

              end

            + case

                when (t2.stats & 1)<>0

                  then ', ignore duplicate keys'

                  else ''

              end

            + case

                when (t2.stats & 2)<>0

                  then ', unique'

                  else ''

              end

            + case

                when (t2.stats & 4)<>0

                  then ', ignore duplicate rows'

                  else ''

              end

            + case

                when (t2.stats & 64)<>0

                  then ', statistics'

                  else

                    case

                      when (t2.stats & 32)<>0

                        then ', hypothetical'

                        else ''

                    end

              end

            + case

                when (t2.stats & 2048)<>0

                  then ', primary_key'

                  else ''

              end

            + case

                when (t2.stats & 4096)<>0

                  then ', unique key'

                  else ''

              end

            + case

                when (t2.stats & 8388608)<>0

                  then ', auto create'

                  else ''

                end

            + case

                when (t2.stats & 16777216)<>0

                  then ', stats no recompute'

                  else ''

              end

            + ' located on '

            + t2.groupname) as index_description

    , t2.index_keys as index_keys

 FROM #indextable t1

INNER JOIN #indextable t2 ON t1.table_name = t2.table_name

                         AND t1.index_name != t2.index_name

                         AND t1.index_keys like t2.index_keys + ',' + '%'

                         AND LTRIM(RTRIM(t1.index_keys)) != LTRIM(RTRIM(t2.index_keys))

ORDER BY t1.table_name

       , t1.index_name

DROP TABLE #indextable

-- There are too many to review right now, so I shall save that for a future post 🙂

Rate

You rated this post out of 5. Change rating

Share

Share

Rate

You rated this post out of 5. Change rating