Because different customers use software in different ways, not every customer will benefit from exactly the same database-level indexes.

As a best practice, when users complain about database performance in a specific area of the application, or when performance tuning in general, I like to let the customer run with the application for a few days, and then use a query such as the one included below (adapted from Jeff Garbus at Soaring Eagle: https://mssqlperformance.blogspot.com):

–Source: Jeff Garbus from Soaring Eagle – Blog: https://mssqlperformance.blogspot.com/
–DRM – 2020-05-04 – Adapted by Darren to deal with mixed SQL Environments, include table name in index name, deal with table names containing spaces, etc.
–Use this SQL Script to identify indexes that if added could help improve performance.
–IMPORTANT: Do not BLINDLY implement the script recommendations.  For example, if the SAME TABLE is mentioned multiple times, then
–           it may be better to COMBINE the recommendations of multiple statements into a single one.
–           If you need help, Soaring Eagle. 
DECLARE @Edition varchar(50)
SET @Edition = CONVERT(varchar(50), SERVERPROPERTY(‘Edition’))
DECLARE @bEnterpriseEdition bit
IF (LEFT(@Edition, 9) = ‘Enterpris’ OR LEFT(@Edition, 9) = ‘Developer’)
SET @bEnterpriseEdition = 1

SELECT
      ‘CREATE INDEX IX_’
            + REPLACE(obj.Name, ‘ ‘, ”) +’_’
            + replace(replace(replace (equality_columns, ‘[‘, ”),’]’,”),’, ‘,’_’)
            + ‘ ON ‘
            + sch.name COLLATE SQL_Latin1_General_CP1_CI_AS + ‘.’ + QuoteName(obj.name)
            + ‘ (‘
            + equality_columns
             + CASE WHEN inequality_columns IS NULL
                   THEN ”
                   ELSE ‘,’ +  inequality_columns
               END
            + ‘)’
            + CASE WHEN included_columns IS NOT NULL
                   THEN ‘ INCLUDE (‘ + ISNULL(included_columns,”) + ‘) ‘
                   ELSE ”
               END
            + CASE WHEN @bEnterpriseEdition = 1
                   THEN ‘ WITH (online = ON)’
                    ELSE ”
              END
            + ‘ — ‘ + CONVERT (varchar, avg_user_impact) + ‘% anticipated impact’
      FROM sys.dm_db_missing_index_details mid
        JOIN sys.dm_db_missing_index_groups mig
            ON mid.index_handle = mig.index_handle
        JOIN sys.dm_db_missing_index_group_stats migs
             ON migs.group_handle = mig.index_group_handle
        JOIN sys.objects obj
            ON obj.object_id = mid.object_id
        JOIN sys.schemas sch
            ON obj.schema_id = sch.schema_id
      WHERE
        database_id = db_id()
        AND avg_user_impact > 60
        AND equality_columns IS NOT NULL
      ORDER BY
        obj.name
        , equality_columns
         , inequality_columns
        , included_columns

The output of this script should be reviewed carefully to see if the tables / recommendations make sense for the specific scenario.  Remember that there is a cost for implementing index changes that may outweigh the benefits.  The most common change that I make to the results from the above is to combine multiple recommendations for the same index into a single index with more elements in the INCLUDE() section.

For Blue Link employees reading this Blog, a version of the above is now available as IndexCreationRecommendationPROC().

Advertisement