Heute Morgen hat ein Kunde über Performance Probleme in einer Anwendung Bescheid gegeben. Der Anwendungsserver sieht gut aus (CPU/RAM/Plattenplatz), auf die DB komme ich auch und die Anwendung reagiert. Hmmmm….
„Vielleicht fehlen Indizes in der DB?“, dachte ich mir. „Kann man das irgendwo klicken?“ war die zweite Frage. „Im SQL Server kann man doch alles irgendwie abfragen, aber wie?“ war meine dritte Frage, mit der ich auf eine große Suchmaschine los bin.
Und siehe da, es gibt bei Microsoft was zu dem Thema unter https://technet.microsoft.com/en-us/library/ms345417(v=sql.105).aspx und ich habe von Basit A. Farooq (@BasitAali) einen Eintrag in seinem Blog gefunden: Find missing indexes using SQL Servers index related DMVs . Danke!
Das von Basit vorgestellte Skript tut einen guten Dienst beim Auffinden und sogar beim Erstellen von Indexskripts. Benutzt werden dabei die Dynamic Management Objects [sys].[dm_db_missing_index_group_stats], [sys].[dm_db_missing_index_groups] und [sys].[dm_db_missing_index_details]:
SELECT CAST(SERVERPROPERTY('ServerName') AS [nvarchar](256)) AS [SQLServer] ,db.[database_id] AS [DatabaseID] ,db.[name] AS [DatabaseName] ,id.[object_id] AS [ObjectID] ,id.[statement] AS [FullyQualifiedObjectName] ,id.[equality_columns] AS [EqualityColumns] ,id.[inequality_columns] AS [InEqualityColumns] ,id.[included_columns] AS [IncludedColumns] ,gs.[unique_compiles] AS [UniqueCompiles] ,gs.[user_seeks] AS [UserSeeks] ,gs.[user_scans] AS [UserScans] ,gs.[last_user_seek] AS [LastUserSeekTime] ,gs.[last_user_scan] AS [LastUserScanTime] ,gs.[avg_total_user_cost] AS [AvgTotalUserCost] ,gs.[avg_user_impact] AS [AvgUserImpact] ,gs.[system_seeks] AS [SystemSeeks] ,gs.[system_scans] AS [SystemScans] ,gs.[last_system_seek] AS [LastSystemSeekTime] ,gs.[last_system_scan] AS [LastSystemScanTime] ,gs.[avg_total_system_cost] AS [AvgTotalSystemCost] ,gs.[avg_system_impact] AS [AvgSystemImpact] ,gs.[user_seeks] * gs.[avg_total_user_cost] * (gs.[avg_user_impact] * 0.01) AS [IndexAdvantage] ,'CREATE INDEX [Missing_IXNC_' + OBJECT_NAME(id.[object_id], db.[database_id]) + '_' + REPLACE(REPLACE(REPLACE(ISNULL(id.[equality_columns], ''), ', ', '_'), '[', ''), ']', '') + CASE WHEN id.[equality_columns] IS NOT NULL AND id.[inequality_columns] IS NOT NULL THEN '_' ELSE '' END + REPLACE(REPLACE(REPLACE(ISNULL(id.[inequality_columns], ''), ', ', '_'), '[', ''), ']', '') + '_' + LEFT(CAST(NEWID() AS [nvarchar](64)), 5) + ']' + ' ON ' + id.[statement] + ' (' + ISNULL(id.[equality_columns], '') + CASE WHEN id.[equality_columns] IS NOT NULL AND id.[inequality_columns] IS NOT NULL THEN ',' ELSE '' END + ISNULL(id.[inequality_columns], '') + ')' + ISNULL(' INCLUDE (' + id.[included_columns] + ')', '') AS [ProposedIndex] ,CAST(CURRENT_TIMESTAMP AS [smalldatetime]) AS [CollectionDate] FROM [sys].[dm_db_missing_index_group_stats] gs WITH (NOLOCK) INNER JOIN [sys].[dm_db_missing_index_groups] ig WITH (NOLOCK) ON gs.[group_handle] = ig.[index_group_handle] INNER JOIN [sys].[dm_db_missing_index_details] id WITH (NOLOCK) ON ig.[index_handle] = id.[index_handle] INNER JOIN [sys].[databases] db WITH (NOLOCK) ON db.[database_id] = id.[database_id] WHERE id.[database_id] > 4 -- Remove this to see for entire instance ORDER BY [IndexAdvantage] DESC OPTION (RECOMPILE);
Cooles Skript und nochmal Danke/Thanx Basit!