diff --git a/Addin.SSMS2018/Addin.SSMS2018.vbproj b/Addin.SSMS2018/Addin.SSMS2018.vbproj index 98a55fc..337964b 100644 --- a/Addin.SSMS2018/Addin.SSMS2018.vbproj +++ b/Addin.SSMS2018/Addin.SSMS2018.vbproj @@ -3,6 +3,7 @@ 16.0 $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) + On @@ -10,6 +11,9 @@ Binary + + false + Debug @@ -20,7 +24,7 @@ Library SSMS2018Addin SSMS2018Addin - v4.7.2 + v4.8 true true true @@ -44,7 +48,7 @@ prompt 41999,42016,42017,42018,42019,42020,42021,42022,42032,42036 True - C:\Program Files %28x86%29\Microsoft SQL Server Management Studio 18\Common7\IDE\Extensions\ + C:\Program Files %28x86%29\Microsoft SQL Server Management Studio 19\Common7\IDE\Extensions\ pdbonly @@ -90,7 +94,7 @@ - ..\..\..\..\Program Files (x86)\Microsoft SQL Server Management Studio 18\Common7\IDE\Extensions\Application\Microsoft.SqlServer.TransactSql.ScriptDom.dll + ..\..\..\..\..\..\..\Program Files (x86)\Microsoft SQL Server Management Studio 19\Common7\IDE\Extensions\Application\Microsoft.SqlServer.TransactSql.ScriptDom.dll False diff --git a/Addin.SSMS2018/My Project/AssemblyInfo.vb b/Addin.SSMS2018/My Project/AssemblyInfo.vb index ba9a361..60dde18 100644 --- a/Addin.SSMS2018/My Project/AssemblyInfo.vb +++ b/Addin.SSMS2018/My Project/AssemblyInfo.vb @@ -8,13 +8,13 @@ Imports System.Runtime.InteropServices ' associated with an assembly. - + diff --git a/Addin.SSMS2018/SettingForm.Designer.vb b/Addin.SSMS2018/SettingForm.Designer.vb index 4484a5e..9995104 100644 --- a/Addin.SSMS2018/SettingForm.Designer.vb +++ b/Addin.SSMS2018/SettingForm.Designer.vb @@ -77,7 +77,7 @@ Partial Class SettingForm 'ComboBoxParserVersion ' Me.ComboBoxParserVersion.FormattingEnabled = True - Me.ComboBoxParserVersion.Items.AddRange(New Object() {"SQL Server 2008", "SQL Server 2012", "SQL Server 2014", "SQL Server 2016", "SQL Server 2017", "SQL Server 2019"}) + Me.ComboBoxParserVersion.Items.AddRange(New Object() {"SQL Server 2008", "SQL Server 2012", "SQL Server 2014", "SQL Server 2016", "SQL Server 2017", "SQL Server 2019", "SQL Server 2022"}) Me.ComboBoxParserVersion.Location = New System.Drawing.Point(136, 30) Me.ComboBoxParserVersion.Name = "ComboBoxParserVersion" Me.ComboBoxParserVersion.Size = New System.Drawing.Size(316, 21) diff --git a/Addin.SSMS2018/ToolWindow1Control.xaml.vb b/Addin.SSMS2018/ToolWindow1Control.xaml.vb index f1e4e7b..5062e3e 100644 --- a/Addin.SSMS2018/ToolWindow1Control.xaml.vb +++ b/Addin.SSMS2018/ToolWindow1Control.xaml.vb @@ -201,8 +201,10 @@ Partial Public Class ToolWindow1Control SqlParser = New TSql140Parser(False) ElseIf TargetVersion = "SQL Server 2019" Then SqlParser = New TSql150Parser(False) + ElseIf TargetVersion = "SQL Server 2022" Then + SqlParser = New TSql160Parser(False) Else - SqlParser = New TSql140Parser(False) + SqlParser = New TSql150Parser(False) End If Dim parseErrors As IList(Of ParseError) = New List(Of ParseError) @@ -219,28 +221,47 @@ Partial Public Class ToolWindow1Control End If + '--------------------------------------------------------------- + ' This is how you can strip off all comments, but keep the format on + 'Dim resultScript = "" + 'For Each Item In result.ScriptTokenStream + ' If Item.TokenType = TSqlTokenType.MultilineComment _ + ' Or Item.TokenType = TSqlTokenType.SingleLineComment Then + ' Continue For + ' End If + ' resultScript = resultScript + Item.Text + 'Next + '--------------------------------------------------------------- + ' Still need to find how to format the script and keep comments in the text + '--------------------------------------------------------------- - - Dim StrAdd2 = "" Dim Gen As SqlScriptGenerator = Nothing If TargetVersion = "SQL Server 2008" Then Gen = New Sql100ScriptGenerator + Gen.Options.SqlVersion = SqlVersion.Sql100 ElseIf TargetVersion = "SQL Server 2012" Then Gen = New Sql110ScriptGenerator + Gen.Options.SqlVersion = SqlVersion.Sql110 ElseIf TargetVersion = "SQL Server 2014" Then Gen = New Sql120ScriptGenerator + Gen.Options.SqlVersion = SqlVersion.Sql120 ElseIf TargetVersion = "SQL Server 2016" Then Gen = New Sql130ScriptGenerator + Gen.Options.SqlVersion = SqlVersion.Sql130 ElseIf TargetVersion = "SQL Server 2017" Then Gen = New Sql140ScriptGenerator + Gen.Options.SqlVersion = SqlVersion.Sql140 ElseIf TargetVersion = "SQL Server 2019" Then Gen = New Sql150ScriptGenerator + Gen.Options.SqlVersion = SqlVersion.Sql150 + ElseIf TargetVersion = "SQL Server 2022" Then + Gen = New Sql160ScriptGenerator + Gen.Options.SqlVersion = SqlVersion.Sql160 Else - Gen = New Sql140ScriptGenerator + Gen = New Sql150ScriptGenerator End If - Gen.Options.IncludeSemicolons = False Gen.Options.AlignClauseBodies = False Gen.GenerateScript(result, ResultCode) diff --git a/QueryTemplates/Blocking/Historical data.sql b/QueryTemplates/Blocking/Historical data.sql deleted file mode 100644 index 40a89b2..0000000 --- a/QueryTemplates/Blocking/Historical data.sql +++ /dev/null @@ -1,19 +0,0 @@ -SELECT TOP 100 * -FROM dba_scrap_book.dbo.blocking_status AS bs -ORDER BY ts desc - -SELECT TOP 100 * -FROM dba_scrap_book.dbo.blocking_process AS bs -ORDER BY ts desc - -;WITH AllProcesses AS ( -SELECT CAST(EventInfo AS NVARCHAR(4000)) AS EventInfo, spid, MAX(ts) AS ts - FROM [dba_scrap_book].[dbo].[blocking_process] -WHERE ts > DATEADD(hour, -3, GETDATE()) -Group BY CAST(EventInfo AS NVARCHAR(4000)), spid -) -SELECT * - FROM [dba_scrap_book].[dbo].[blocking_status] S - LEFT JOIN AllProcesses P ON S.spid = P.spid -WHERE S.ts > DATEADD(hour, -3, GETDATE()) -ORDER BY S.ts DESC \ No newline at end of file diff --git a/QueryTemplates/Common Scripts/Database mirroring.sql b/QueryTemplates/Common Scripts/Database mirroring.sql index 44787f9..40357e3 100644 --- a/QueryTemplates/Common Scripts/Database mirroring.sql +++ b/QueryTemplates/Common Scripts/Database mirroring.sql @@ -5,10 +5,13 @@ DROP ENDPOINT [Mirroring] GO CREATE ENDPOINT [Mirroring] - STATE=STARTED + STATE = STARTED AS TCP (LISTENER_PORT = 5022, LISTENER_IP = ALL) - FOR DATA_MIRRORING (ROLE = PARTNER, AUTHENTICATION = CERTIFICATE DatabaseMirroring -, ENCRYPTION = DISABLED) + FOR DATA_MIRRORING ( + ROLE = PARTNER, + AUTHENTICATION = CERTIFICATE DatabaseMirroring, + ENCRYPTION = REQUIRED ALGORITHM AES + ) GO CREATE MASTER KEY ENCRYPTION BY PASSWORD = ''; diff --git a/QueryTemplates/Common Scripts/change-db-owner-in-busy-database.sql b/QueryTemplates/Common Scripts/change-db-owner-in-busy-database.sql new file mode 100644 index 0000000..48b0d46 --- /dev/null +++ b/QueryTemplates/Common Scripts/change-db-owner-in-busy-database.sql @@ -0,0 +1,15 @@ +-- 1st session +ALTER AUTHORIZATION ON DATABASE::[db] TO [sa] +GO + +--2nd session +DECLARE @bloked AS INT = NULL; + +SELECT @bloked = blocked +FROM sys.sysprocesses +WHERE spid = <1st session @@SPID>; + +IF @bloked > 0 + EXECUTE ('kill ' + @bloked); + +WAITFOR DELAY '00:00:00.100'; diff --git a/QueryTemplates/Common Scripts/column-store-indexes.sql b/QueryTemplates/Common Scripts/column-store-indexes.sql index 37c15ec..c4176c4 100644 --- a/QueryTemplates/Common Scripts/column-store-indexes.sql +++ b/QueryTemplates/Common Scripts/column-store-indexes.sql @@ -1,3 +1,4 @@ +/* -- select all columnstore indexes SELECT OBJECT_SCHEMA_NAME(OBJECT_ID) SchemaName, @@ -18,16 +19,22 @@ SELECT * FROM sys.dm_db_column_store_row_group_physical_stats WHERE object_id = object_id('TableName') ORDER BY row_group_id; - +*/ -- get some stats around CIX - helps to see which partitions need to be rebuilt -SELECT object_name(object_id) - ,partition_number - ,FORMAT(sum(row_group_id), 'N0') AS row_group_count - ,FORMAT(sum(total_rows), 'N0') AS row_count - ,FORMAT(sum(size_in_bytes), 'N0') AS size_in_bytes - ,FORMAT(sum(size_in_bytes) / sum(total_rows), 'N0') AS size_per_row -FROM sys.dm_db_column_store_row_group_physical_stats -WHERE object_name(object_id) LIKE ' table name %' -GROUP BY object_name(object_id) - ,partition_number -ORDER BY partition_number; +SELECT OBJECT_SCHEMA_NAME(ps.[object_id]) AS schemaName, + OBJECT_NAME(ps.[object_id]) AS tableName, + ps.partition_number, + p.data_compression_desc, + FORMAT(SUM(ps.row_group_id), 'N0') AS row_group_count, + FORMAT(SUM(ps.total_rows), 'N0') AS row_count, + FORMAT(SUM(ps.deleted_rows), 'N0') AS deleted_rows, + FORMAT(SUM(ps.size_in_bytes) / 1024 / 1024, 'N0') AS size_in_mbytes, + FORMAT(SUM(ps.size_in_bytes) / sum(total_rows), 'N0') AS size_per_row, + CONCAT('ALTER INDEX [', i.[name], '] ON ', OBJECT_SCHEMA_NAME(ps.[object_id]), '.', OBJECT_NAME(ps.[object_id]), + ' REBUILD PARTITION = ', ps.partition_number, ' WITH (DATA_COMPRESSION = COLUMNSTORE, ONLINE = ON, SORT_IN_TEMPDB = ON /*, MAXDOP = 8 */); +GO') AS rebuiltCommand +FROM sys.dm_db_column_store_row_group_physical_stats AS ps + INNER JOIN sys.indexes AS i ON ps.[object_id] = i.[object_id] AND ps.index_id = i.index_id + INNER JOIN sys.partitions p ON ps.partition_number = p.partition_number AND ps.[object_id] = p.[object_id] AND ps.index_id = p.index_id +GROUP BY ps.[object_id], ps.partition_number, p.data_compression_desc, i.[name] +ORDER BY schemaName, tableName, ps.partition_number; diff --git a/QueryTemplates/Common Scripts/partitions-stats.sql b/QueryTemplates/Common Scripts/partitions-stats.sql index 3273c5a..e50e328 100644 --- a/QueryTemplates/Common Scripts/partitions-stats.sql +++ b/QueryTemplates/Common Scripts/partitions-stats.sql @@ -6,6 +6,7 @@ SELECT p.index_id AS IndexID, --ds.name AS PartitionScheme, --pf.name AS PartitionFunction, + --CONCAT('ALTER PARTITION FUNCTION ', pf.name, '() MERGE RANGE (''', cast(prv_left.value as datetime), ''')') AS PartitionFunctionMerge p.partition_number AS PartitionNumber, --fg.name AS FileGroupName, prv_left.value AS LowerBoundaryValue, @@ -26,9 +27,10 @@ LEFT JOIN sys.partition_range_values AS prv_right ON ps.function_id = prv_right. WHERE p.index_id = 1 /* only show clustered index */ --AND OBJECT_NAME(p.object_id) = '' + --AND SCHEMA_NAME(o.schema_id) = '' --AND i.[name] = '' --AND p.partition_number = 0 - --AND p.[rows] > 0 + --AND p.[rows] > 0 ORDER BY ObjectName, IndexID, PartitionNumber diff --git a/QueryTemplates/Common Scripts/rename-database.sql b/QueryTemplates/Common Scripts/rename-database.sql new file mode 100644 index 0000000..a44a262 --- /dev/null +++ b/QueryTemplates/Common Scripts/rename-database.sql @@ -0,0 +1,8 @@ +USE master; +GO +ALTER DATABASE [db] SET SINGLE_USER WITH ROLLBACK IMMEDIATE; +GO +ALTER DATABASE [db] MODIFY NAME = [db_OLD]; +GO +ALTER DATABASE [db_OLD] SET MULTI_USER; +GO diff --git a/QueryTemplates/Common Scripts/script-database-level-permissions.sql b/QueryTemplates/Common Scripts/script-database-level-permissions.sql index 3cc0af1..eba113c 100644 --- a/QueryTemplates/Common Scripts/script-database-level-permissions.sql +++ b/QueryTemplates/Common Scripts/script-database-level-permissions.sql @@ -4,6 +4,8 @@ DROP TABLE IF EXISTS #AllPermissions; DROP TABLE IF EXISTS #FilterByUsers; +DROP TABLE IF EXISTS #Users; + CREATE TABLE #AllPermissions (id int IDENTITY(1,1), [codeSQL] varchar(1024)); CREATE TABLE #FilterByUsers (userName varchar(64)); @@ -38,7 +40,7 @@ END --Script the database users --====================================================== SELECT principal_id INTO #users FROM sys.database_principals WHERE type IN ('U', 'G', 'S') AND principal_id > 4 - AND (name in (SELECT F.userName FROM #FilterByUsers F) OR (SELECT COUNT(*) FROM #FilterByUsers) = 0); + AND (name COLLATE Latin1_General_CI_AS in (SELECT F.userName FROM #FilterByUsers F) OR (SELECT COUNT(*) FROM #FilterByUsers) = 0); IF (SELECT COUNT(*) FROM #users) = 0 BEGIN @@ -193,7 +195,7 @@ BEGIN FROM sys.database_permissions dpm INNER JOIN sys.database_principals dp ON dpm.grantee_principal_id = dp.principal_id WHERE dp.principal_id > 4 AND dpm.class = 0 --AND dpm.type = 'CO' - AND (dp.name in (SELECT F.userName FROM #FilterByUsers F) OR (SELECT COUNT(*) FROM #FilterByUsers) = 0) + AND (dp.name COLLATE Latin1_General_CI_AS in (SELECT F.userName FROM #FilterByUsers F) OR (SELECT COUNT(*) FROM #FilterByUsers) = 0) END @@ -222,11 +224,12 @@ BEGIN , maj_ID NVARCHAR(128) , name NVARCHAR(128) , pr_name NVARCHAR(128) + , column_name NVARCHAR(128) ) DECLARE @state_desc VARCHAR(60) DECLARE @perm_name NVARCHAR(128), @sch_name NVARCHAR(128), @maj_ID NVARCHAR(128) - DECLARE @name NVARCHAR(128), @pr_name NVARCHAR(128) + DECLARE @name NVARCHAR(128), @pr_name NVARCHAR(128), @column_name NVARCHAR(128) INSERT INTO #objgrants SELECT CASE dbpe.[state] WHEN 'W' THEN 'GRANT' @@ -238,29 +241,35 @@ BEGIN , dbpr.name AS name , CASE dbpe.[state] WHEN 'W' THEN '] WITH GRANT OPTION' ELSE ']' END AS pr_name + , ISNULL((select al.name as ColumnName from sys.database_permissions dp + inner join sys.all_columns al + on dp.minor_id = al.column_id + and al.object_id = dbpe.major_id + where dp.major_id = dbpe.major_id and dp.minor_id > 0 and dbpe.minor_id = dp.minor_id and dp.class_desc = 'OBJECT_OR_COLUMN'), '') as ColumnName FROM sys.database_permissions dbpe INNER JOIN sys.database_principals dbpr ON dbpr.principal_id = dbpe.grantee_principal_id INNER JOIN sys.objects obj ON dbpe.major_id = obj.object_id INNER JOIN sys.schemas sch ON obj.schema_id = sch.schema_id WHERE obj.type NOT IN ('IT','S','X') - AND (dbpr.name in (SELECT F.userName FROM #FilterByUsers F) OR (SELECT COUNT(*) FROM #FilterByUsers) = 0) + AND (dbpr.name COLLATE Latin1_General_CI_AS in (SELECT F.userName FROM #FilterByUsers F) OR (SELECT COUNT(*) FROM #FilterByUsers) = 0) ORDER BY dbpr.name, obj.name - + WHILE (SELECT COUNT(*) FROM #objgrants) > 0 BEGIN SELECT TOP 1 @state_desc = state_desc, @perm_name = perm_name, @sch_name = sch_name, - @maj_ID = maj_ID, @name = name, @pr_name = pr_name FROM #objgrants + @maj_ID = maj_ID, @name = name, @pr_name = pr_name, @column_name = column_name FROM #objgrants INSERT INTO #AllPermissions ([codeSQL]) SELECT @state_desc + ' ' + @perm_name + - ' ON [' + @sch_name + '].[' + @maj_ID + '] TO [' + @name + @pr_name + ' ON [' + @sch_name + '].[' + @maj_ID + ']' + CASE WHEN @column_name = '' THEN '' ELSE CONCAT('(', @column_name, ')') END + ' TO [' + @name + @pr_name DELETE FROM #objgrants WHERE state_desc = @state_desc AND perm_name = @perm_name - AND sch_name = @sch_name AND maj_ID = @maj_ID AND name = @name AND pr_name = @pr_name + AND sch_name = @sch_name AND maj_ID = @maj_ID AND name = @name AND pr_name = @pr_name AND column_name = @column_name END DROP TABLE #objgrants + END @@ -285,7 +294,7 @@ BEGIN INNER JOIN sys.database_role_members drm ON dp.principal_id = drm.role_principal_id INNER JOIN sys.database_principals dp2 ON drm.member_principal_id = dp2.principal_id WHERE dp2.principal_id > 4 AND dp2.type <> 'R' - AND (dp2.name in (SELECT F.userName FROM #FilterByUsers F) OR (SELECT COUNT(*) FROM #FilterByUsers) = 0) + AND (dp2.name COLLATE Latin1_General_CI_AS in (SELECT F.userName FROM #FilterByUsers F) OR (SELECT COUNT(*) FROM #FilterByUsers) = 0) END diff --git a/QueryTemplates/Common Scripts/space-used-per-database-file.sql b/QueryTemplates/Common Scripts/space-used-per-database-file.sql index 49d3cef..8275054 100644 --- a/QueryTemplates/Common Scripts/space-used-per-database-file.sql +++ b/QueryTemplates/Common Scripts/space-used-per-database-file.sql @@ -44,7 +44,7 @@ SELECT ,[PercentFree] ,[file_id] ,[FilegroupName] -FROM [DBA].[dbo].[FileSizeStats] -ORDER BY AvailableSpaceInMB DESC; +FROM #Stats +ORDER BY 6 DESC; -DROP TABLE #Stats; +-- DROP TABLE #Stats; diff --git a/QueryTemplates/Common Scripts/tables-information.sql b/QueryTemplates/Common Scripts/tables-information.sql deleted file mode 100644 index 813c6a7..0000000 --- a/QueryTemplates/Common Scripts/tables-information.sql +++ /dev/null @@ -1,94 +0,0 @@ -WITH RowsStatistics -AS (SELECT SCHEMA_NAME(SO.schema_id) AS SchemaName, - OBJECT_NAME(PS.object_id) AS TableName, - PS.object_id AS ObjectId, - SO.create_date, - COUNT(DISTINCT ps.partition_number) as PartitionCount, - SUM(row_count) AS RowsCount - FROM sys.dm_db_partition_stats AS PS - INNER JOIN - sys.objects AS SO - ON PS.OBJECT_ID = SO.object_id - WHERE PS.index_id < 2 - AND PS.OBJECT_ID > 100 - AND SCHEMA_NAME(SO.schema_id) <> 'sys' - GROUP BY SCHEMA_NAME(SO.schema_id), OBJECT_NAME(PS.object_id), PS.object_id, SO.create_date), - TableSizes -AS (SELECT t.object_id AS ObjectId, - CAST (ROUND(((SUM(a.used_pages) * 8) / 1024.00), 2) AS NUMERIC (36, 2)) AS UsedSpaceMB, - CAST (ROUND(((SUM(CASE WHEN p.data_compression > 0 THEN a.used_pages ELSE 0 END) * 8) / 1024.00), 2) AS NUMERIC (36, 2)) AS UsedSpaceMB_Compressed - FROM sys.tables AS t - INNER JOIN - sys.indexes AS i - ON t.OBJECT_ID = i.object_id - INNER JOIN - sys.partitions AS p - ON i.object_id = p.OBJECT_ID - AND i.index_id = p.index_id - INNER JOIN - sys.allocation_units AS a - ON p.partition_id = a.container_id - GROUP BY t.object_id), - TableInformation -AS (SELECT NAME, - object_id AS ObjectId, - CASE WHEN NAME IN (SELECT object_name(Parent_object_id) - FROM sys.objects - WHERE type = 'PK') THEN 1 ELSE 0 END AS HasPK, - CASE WHEN NAME IN (SELECT OBJECT_NAME(OBJECT_ID) - FROM sys.indexes AS i - WHERE i.type_desc = 'CLUSTERED' - AND i.object_id = T.object_id) THEN 1 ELSE 0 END AS HasClusteredIndex, - CASE WHEN NAME IN (SELECT object_name(Parent_object_id) - FROM sys.objects - WHERE type = 'PK' - AND object_name(object_id) IN (SELECT name - FROM sys.indexes AS i - WHERE i.type_desc = 'CLUSTERED' - AND i.object_id = T.object_id)) THEN 1 ELSE 0 END AS PKisClustered, - is_replicated - FROM sys.tables AS T - WHERE is_ms_shipped = 0), - LastReadWrites -AS (SELECT object_id AS ObjectID, - MAX(last_user_update) AS [LastUserUpdate], - MAX(last_user_seek) AS [LastUserSeek], - MAX(last_user_scan) AS [LastUserScan], - MAX(last_user_lookup) AS [LastUserLookup], - SUM(user_seeks + user_scans + user_lookups) AS [TotalReads], - SUM(user_updates) AS [TotalWrites] - FROM sys.dm_db_index_usage_stats - WHERE database_id = DB_ID() - GROUP BY object_id) -SELECT DB_NAME() AS DatabaseName, - rs.SchemaName, - rs.TableName, - FORMAT(RS.RowsCount, 'N0') AS RowsCount, - FORMAT(TS.UsedSpaceMB, 'N0') AS UsedSpaceMB, - FORMAT(TS.UsedSpaceMB_Compressed, 'N0') AS UsedSpaceMB_Compressed, - RS.PartitionCount, - TI.HasPK, - TI.HasClusteredIndex, - TI.PKisClustered, - TI.is_replicated, - L.[LastUserUpdate] AS LastWrite, - COALESCE (L.LastUserScan, L.LastUserSeek, L.LastUserLookup) AS LastRead, - L.TotalReads, - L.TotalWrites, - RS.Create_date as CreateDate -FROM RowsStatistics AS RS - FULL OUTER JOIN - TableInformation AS TI - ON RS.ObjectId = TI.ObjectId - LEFT OUTER JOIN - LastReadWrites AS L - ON L.objectId = RS.ObjectId - LEFT OUTER JOIN - TableSizes AS TS - ON TS.ObjectId = TI.ObjectId -WHERE 1 = 1 - --AND rs.TableName IN ('','') - --AND rs.SchemaName = '' - --AND RS.RowsCount > 0 -ORDER BY TS.UsedSpaceMB DESC; - diff --git a/QueryTemplates/Common Scripts/tde-check-status.sql b/QueryTemplates/Common Scripts/tde-check-status.sql index 9f21517..e903e8a 100644 --- a/QueryTemplates/Common Scripts/tde-check-status.sql +++ b/QueryTemplates/Common Scripts/tde-check-status.sql @@ -1,5 +1,5 @@ SELECT - DB_NAME(database_id) AS DatabaseName, + d.[name] AS DatabaseName, encryption_state, encryption_state_desc = CASE encryption_state @@ -17,5 +17,16 @@ SELECT FROM master.sys.certificates AS c WHERE c.thumbprint = a.encryptor_thumbprint), encryptor_thumbprint, - encryptor_type -FROM sys.dm_database_encryption_keys a + encryptor_type, + CONCAT('USE [', d.[name], '] +GO +CREATE DATABASE ENCRYPTION KEY WITH ALGORITHM = AES_256 ENCRYPTION BY SERVER CERTIFICATE [TDE]; +GO +ALTER DATABASE [', d.[name], '] SET ENCRYPTION ON; +GO') AS encryptCommand +FROM sys.databases AS d + LEFT OUTER JOIN sys.dm_database_encryption_keys AS a + ON d.database_id = a.database_id +WHERE d.source_database_id IS NULL + AND d.database_id > 4 +ORDER BY DatabaseName; diff --git a/QueryTemplates/Common Scripts/tempdb-alter.sql b/QueryTemplates/Common Scripts/tempdb-alter.sql new file mode 100644 index 0000000..7165bf0 --- /dev/null +++ b/QueryTemplates/Common Scripts/tempdb-alter.sql @@ -0,0 +1,20 @@ +SELECT CONCAT( + 'ALTER DATABASE tempdb MODIFY FILE (', + 'NAME = ', QUOTENAME(f.[name]), ', ', + 'FILENAME = ', QUOTENAME( + CONCAT('Z:\MSSQL\DATA\', f.[name], + CASE WHEN f.type = 1 THEN '.ldf' ELSE '.mdf' END + ) + , ''''), ', ', + 'SIZE = ', FORMAT(f.size * 8.0 / 1024, 'N0'), 'MB, ', + 'FILEGROWTH = ', + CASE + WHEN f.is_percent_growth = 1 + THEN CONCAT(f.growth, '%') + ELSE CONCAT(FORMAT(f.growth * 8.0 / 1024, 'N0'), 'MB') + END, + ');' +) AS AlterCommand +FROM sys.master_files AS f +WHERE f.database_id = DB_ID(N'tempdb') +ORDER BY f.[file_id]; diff --git a/QueryTemplates/Common Scripts/trigger-properties.sql b/QueryTemplates/Common Scripts/trigger-properties.sql new file mode 100644 index 0000000..9bacf7a --- /dev/null +++ b/QueryTemplates/Common Scripts/trigger-properties.sql @@ -0,0 +1,39 @@ +SELECT sysobjects.name AS trigger_name, + USER_NAME(sysobjects.uid) AS trigger_owner, + s.name AS table_schema, + OBJECT_NAME(parent_obj) AS table_name, + OBJECTPROPERTY(id, 'ExecIsUpdateTrigger') AS isupdate, + OBJECTPROPERTY(id, 'ExecIsDeleteTrigger') AS isdelete, + OBJECTPROPERTY(id, 'ExecIsInsertTrigger') AS isinsert, + OBJECTPROPERTY(id, 'ExecIsAfterTrigger') AS isafter, + OBJECTPROPERTY(id, 'ExecIsInsteadOfTrigger') AS isinsteadof, + OBJECTPROPERTY(id, 'ExecIsTriggerDisabled') AS [disabled] +FROM sysobjects + INNER JOIN sysusers + ON sysobjects.uid = sysusers.uid + INNER JOIN sys.tables AS t + ON sysobjects.parent_obj = t.object_id + INNER JOIN sys.schemas AS s + ON t.schema_id = s.schema_id +WHERE sysobjects.type = 'TR' + --AND sysobjects.name LIKE '%%' +ORDER BY isinsert DESC; + +SELECT sys.tables.name, + sys.triggers.name, + sys.trigger_events.type, + sys.trigger_events.type_desc, + is_first, + is_last, + sys.triggers.create_date, + sys.triggers.modify_date +FROM sys.triggers + INNER JOIN sys.trigger_events + ON sys.trigger_events.object_id = sys.triggers.object_id + INNER JOIN sys.tables + ON sys.tables.object_id = sys.triggers.parent_id +WHERE 1 = 1 + -- AND sys.trigger_events.type_desc = 'UPDATE' + -- AND sys.triggers.name LIKE '%%' + -- AND is_last = 0 +ORDER BY modify_date; diff --git a/QueryTemplates/Performance/index-fragmentation.sql b/QueryTemplates/Performance/index-fragmentation.sql index a430578..c1143cb 100644 --- a/QueryTemplates/Performance/index-fragmentation.sql +++ b/QueryTemplates/Performance/index-fragmentation.sql @@ -1,36 +1,36 @@ -SELECT dbschemas.[name] as 'Schema', - dbtables.[name] as 'Table', - dbindexes.[index_id] as 'IndexID', - dbindexes.[name] as 'Index', - indexstats.partition_number, - FORMAT(AVG(indexstats.avg_fragmentation_in_percent), 'N2') AS avg_fragmentation_in_percent, - FORMAT(SUM(indexstats.page_count), 'N0') AS page_count, - FORMAT(SUM(indexstats.page_count * 8 / 1024), 'N0') AS index_size_mb, - 'ALTER INDEX ['+dbindexes.[name]+'] ON [' + dbschemas.name + '].['+dbtables.[name]+'] REORGANIZE PARTITION = ' - + CASE WHEN EXISTS(SELECT TOP 1 1 FROM sys.partition_schemes s WHERE s.data_space_id = dbindexes.data_space_id) - THEN CAST(indexstats.partition_number AS VARCHAR(3)) ELSE 'ALL' END + ';' AS CmdReorg, - 'ALTER INDEX ['+dbindexes.[name]+'] ON [' + dbschemas.name + '].['+dbtables.[name]+'] REBUILD PARTITION = ' - + CASE WHEN EXISTS(SELECT TOP 1 1 FROM sys.partition_schemes s WHERE s.data_space_id = dbindexes.data_space_id) - THEN CAST(indexstats.partition_number AS VARCHAR(3)) ELSE 'ALL' END - + ' WITH (' - + CASE WHEN ISNULL(dbindexes.[type_desc], '') LIKE '%COLUMNSTORE' - THEN 'ONLINE = OFF, ' - ELSE 'ONLINE = ON (WAIT_AT_LOW_PRIORITY (MAX_DURATION = 1 MINUTES, ABORT_AFTER_WAIT = SELF)), ' - END - + 'SORT_IN_TEMPDB = ON, MAXDOP = 4);' AS CmdRebuild -FROM sys.dm_db_index_physical_stats (DB_ID(), NULL, NULL, NULL, NULL) AS indexstats -INNER JOIN sys.tables dbtables on dbtables.[object_id] = indexstats.[object_id] -INNER JOIN sys.schemas dbschemas on dbtables.[schema_id] = dbschemas.[schema_id] -INNER JOIN sys.indexes AS dbindexes ON dbindexes.[object_id] = indexstats.[object_id] - AND indexstats.index_id = dbindexes.index_id -WHERE indexstats.database_id = DB_ID() - AND indexstats.page_count > 100 - AND dbindexes.[name] IS NOT NULL -GROUP BY dbschemas.[name], - dbtables.[name], - dbindexes.[index_id], - dbindexes.[name], - dbindexes.[type_desc], - indexstats.partition_number, - dbindexes.data_space_id -ORDER BY AVG(indexstats.avg_fragmentation_in_percent) DESC +SELECT s.[name] AS SchemaName, + t.[name] AS TableName, + i.[index_id] AS IndexID, + i.[name] AS IndexName, + ips.partition_number AS PartitionNumber, + part.data_compression_desc AS DataComprDesc, + FORMAT(ips.avg_fragmentation_in_percent, 'N2') AS AvgFragPercent, + FORMAT(ips.page_count, 'N0') AS [PageCount], + FORMAT(ips.page_count * 8 / 1024, 'N0') AS IndexSizeMb, + CASE WHEN i.[type_desc] IN ('CLUSTERED', 'NONCLUSTERED') + THEN CONCAT('ALTER INDEX [', i.[name], '] ON [', s.[name], '].[', t.[name], '] REORGANIZE PARTITION = ', + IIF (ps.[name] IS NULL, 'ALL', CAST (ips.partition_number AS VARCHAR (4))), ';') ELSE '' END AS CmdReorg, + CASE WHEN i.[type_desc] IN ('HEAP') + THEN CONCAT('ALTER TABLE [', s.[name], '].[', t.[name], '] REBUILD PARTITION = ', + IIF (ps.[name] IS NULL, 'ALL', CAST (ips.partition_number AS VARCHAR (4))), + ' WITH (ONLINE = ON (WAIT_AT_LOW_PRIORITY (MAX_DURATION = 1 MINUTES, ABORT_AFTER_WAIT = SELF)), DATA_COMPRESSION=PAGE, MAXDOP = 4);') + WHEN i.[type_desc] IN ('CLUSTERED', 'NONCLUSTERED') + THEN CONCAT('ALTER INDEX [', i.[name], '] ON [', s.[name], '].[', t.[name], '] REBUILD PARTITION = ', + IIF (ps.[name] IS NULL, 'ALL', CAST (ips.partition_number AS VARCHAR (4))), + ' WITH (ONLINE = ON (WAIT_AT_LOW_PRIORITY (MAX_DURATION = 1 MINUTES, ABORT_AFTER_WAIT = SELF)), ', + 'SORT_IN_TEMPDB = ON, DATA_COMPRESSION=PAGE, MAXDOP = 4);') END AS CmdRebuild +FROM sys.dm_db_index_physical_stats(DB_ID(), NULL, -- OBJECT_ID('dbo.Table'), + NULL, NULL, NULL) AS ips + INNER JOIN sys.tables AS t ON t.[object_id] = ips.[object_id] + INNER JOIN sys.schemas AS s ON t.[schema_id] = s.[schema_id] + INNER JOIN sys.indexes AS i ON i.[object_id] = ips.[object_id] AND ips.index_id = i.index_id + INNER JOIN sys.partitions AS part ON i.[object_id] = part.[object_id] AND i.index_id = part.index_id AND ips.partition_number = part.partition_number + LEFT OUTER JOIN sys.partition_schemes AS ps ON i.data_space_id = ps.data_space_id +WHERE 1 = 1 + -- AND ips.page_count > 100 + -- AND i.[name] IS NOT NULL + -- AND ips.avg_fragmentation_in_percent > 50 + -- AND part.data_compression_desc = 'NONE' +ORDER BY + -- ips.avg_fragmentation_in_percent DESC; + SchemaName, TableName, PartitionNumber, IndexID; diff --git a/QueryTemplates/Performance/physical-index-page-info.sql b/QueryTemplates/Performance/physical-index-page-info.sql new file mode 100644 index 0000000..4102244 --- /dev/null +++ b/QueryTemplates/Performance/physical-index-page-info.sql @@ -0,0 +1,31 @@ +/* + Get stats around physical index pages +*/ +CREATE TABLE #TempDBCC_IND +( + PageFID SMALLINT, + PagePID INT, + IAMFID SMALLINT, + IAMPID INT, + ObjectID INT, + IndexID SMALLINT, + PartitionNumber SMALLINT, + PartitionID BIGINT, + iam_chain_type VARCHAR(100), + PageType TINYINT, + IndexLevel TINYINT, + NextPageFID SMALLINT, + NextPagePID INT, + PrevPageFID SMALLINT, + PrevPagePID INT +) + +INSERT INTO #TempDBCC_IND +EXEC('DBCC IND(''DatabaseName'', ''TableName'', 1) WITH NO_INFOMSGS'); + +SELECT PageFID, + COUNT(*) AS NumberOfPages +FROM #TempDBCC_IND +WHERE PartitionNumber = 1 +GROUP BY PageFID +ORDER BY 2; diff --git a/QueryTemplates/Performance/query-store.sql b/QueryTemplates/Performance/query-store.sql new file mode 100644 index 0000000..ead8c1e --- /dev/null +++ b/QueryTemplates/Performance/query-store.sql @@ -0,0 +1,25 @@ +SELECT DATEADD(hour, DATEDIFF(hour, 0, rs.first_execution_time), 0) AS first_execution, + sum(rs.count_executions) AS count_executions, + sum(rs.count_executions * rs.avg_duration) AS total_duration, + sum(rs.count_executions * rs.avg_duration) / SUM(rs.count_executions) AS avg_duration, + sum(rs.count_executions * rs.avg_cpu_time) / SUM(rs.count_executions) AS avg_cpu_time, + sum(rs.count_executions * rs.avg_logical_io_reads) AS total_logical_io_reads, + sum(rs.count_executions * rs.avg_logical_io_reads) / SUM(rs.count_executions) AS avg_logical_io_reads, + sum(rs.count_executions * rs.avg_physical_io_reads) AS total_physical_io_reads, + sum(rs.count_executions * rs.avg_physical_io_reads) / SUM(rs.count_executions) AS avg_physical_io_reads +FROM sys.query_store_runtime_stats AS rs +WHERE rs.plan_id IN (SELECT p.plan_id + FROM sys.query_store_plan AS p + WHERE p.query_id IN (SELECT q.query_id + FROM sys.query_store_query AS q + WHERE q.object_id = object_id(' %% dbo.Table %% '))) + AND rs.first_execution_time > (GETDATE() - 7) +GROUP BY DATEADD(hour, DATEDIFF(hour, 0, rs.first_execution_time), 0) +ORDER BY 1 DESC; + + +SELECT CAST(query_plan as XML) as queryPlan, * +FROM sys.query_store_plan AS p +WHERE p.query_id IN (SELECT q.query_id + FROM sys.query_store_query AS q + WHERE q.object_id = object_id(' %% dbo.Table %% ')) diff --git a/QueryTemplates/Performance/sp_BlitzCache.sql b/QueryTemplates/Performance/sp_BlitzCache.sql deleted file mode 100644 index cdef437..0000000 --- a/QueryTemplates/Performance/sp_BlitzCache.sql +++ /dev/null @@ -1,2126 +0,0 @@ -USE master; -GO - -IF OBJECT_ID('dbo.sp_BlitzCache') IS NULL - EXEC ('CREATE PROCEDURE dbo.sp_BlitzCache AS RETURN 0;') -GO - -IF OBJECT_ID('dbo.sp_BlitzCache') IS NOT NULL AND OBJECT_ID('##bou_BlitzCacheProcs') IS NOT NULL - EXEC ('DROP TABLE ##bou_BlitzCacheProcs;') -GO - -IF OBJECT_ID('dbo.sp_BlitzCache') IS NOT NULL AND OBJECT_ID('##bou_BlitzCacheResults') IS NOT NULL - EXEC ('DROP TABLE ##bou_BlitzCacheResults;') -GO - -ALTER PROCEDURE dbo.sp_BlitzCache - @get_help BIT = 0, - @top INT = 50, - @sort_order VARCHAR(50) = 'CPU', - @use_triggers_anyway BIT = NULL, - @export_to_excel BIT = 0, - @results VARCHAR(10) = 'simple', - @output_database_name NVARCHAR(128) = NULL , - @output_schema_name NVARCHAR(256) = NULL , - @output_table_name NVARCHAR(256) = NULL , - @configuration_database_name NVARCHAR(128) = NULL , - @configuration_schema_name NVARCHAR(256) = NULL , - @configuration_table_name NVARCHAR(256) = NULL , - @duration_filter DECIMAL(38,4) = NULL , - @hide_summary BIT = 0 , - @ignore_system_db BIT = 1 , - @only_query_hashes VARCHAR(MAX) = NULL , - @ignore_query_hashes VARCHAR(MAX) = NULL , - @query_filter VARCHAR(10) = 'ALL' , - @reanalyze BIT = 0 , - @Whole_cache BIT = 0 /* This will forcibly set @top to 2,147,483,647 */ -WITH RECOMPILE -/****************************************** -sp_BlitzCache (TM) 2014, Brent Ozar Unlimited. -(C) 2014, Brent Ozar Unlimited. -See http://BrentOzar.com/go/eula for the End User Licensing Agreement. - - - -Description: Displays a server level view of the SQL Server plan cache. - -Output: One result set is presented that contains data from the statement, -procedure, and trigger stats DMVs. - -To learn more, visit http://brentozar.com/blitzcache/ -where you can download new versions for free, watch training videos on -how it works, get more info on the findings, and more. To contribute -code and see your name in the change log, submit your improvements & -ideas to https://support.brentozar.com - - - -KNOWN ISSUES: -- This query will not run on SQL Server 2005. -- SQL Server 2008 and 2008R2 have a bug in trigger stats (see below). -- @ignore_query_hashes and @only_query_hashes require a CSV list of hashes - with no spaces between the hash values. - -v2.4.4 - 2015-01-09 - - Fixed output to table. Sort order wasn't being obeyed and users limting - results weren't seeing the same results between displaying to screen and - saving results to a table. - Thanks to Gail Jurey for spotting this! - - Fixed an error where running with reanalyze after export_to_excel would - prevent a summary from being generated. - - Added query plan cost to export_to_excel output. - - Cleaned up export_to_excel output to match column order to screen display. - -v2.4.3 - 2014-11-11 - - Fix to remove confusing implicit conversion checks. Warnings will only be - generated when a plan affecting convert is in place. - -v2.4.2 - 2014-11-04 - - Hotfix - Randall Petty found a stray comma in the export_to_excel output. - -v2.4.1 - 2014-10-31 - - Hotfix - Denis Gobo pointed out that the global temp table names could - conflict with everyone else's global temp table rates. - -v2.4 - 2014-10-31 - - Fixed a logical error in output table detection - thanks to Michael - Bluett for pointing that out. - - Fixed a bug where sorting on average executions broke the query. - Thanks to Andrew Notarian and Calvin Jones for submitting this. - - Added @query_filter to allow output restrictions to only procedures - or individual statements - - Adds a check for trivial execution plans. - - Adds @reanalyze. When set to 1, this re-scans existing results rather - than running all of the logic again. Bonus: contains GOTO. - - Now displaying set options! - -v2.3 - 2014-06-07 - - Added opserver specific output - - Adding a `@only_query_hashes` parameter to limit results to a select set of - query hashes. - - Adding a `@ignore_query_hashes` parameter to exclude specific queries from - analysis. - -v2.2 - 2014-05-20 - - Added sorting on averages - - Added configuration table parameters. Includes help messages for the - allowed parameters and default values. - - Missing index warning now displays the number of missing indexes. - - Changing display to milliseconds instead of microseconds. - - Adding a flag to ignore system databases. This is on by default. - - Correcting a typo found by Michael Zilberstein. Thanks! - - Fixing an XML bug for implicit conversion detection - contributed by Michael Zilberstein. - - Added a check for unparameterized queries. - -v2.1 - 2014-04-30 - - Added @duration_filter. Queries are now filtered during collection based on duration. - - Added results summary table and hide_summary parameter. - - Added check for > 1000 executions per minute. - - Added check for queries with missing indexes. - - Added check for queries with warnings in the execution plan. - - Added check for queries using cursors. - - Query cost will be displayed next to the execution plan for a query. - - Added a check for plan guides and forced plans. - - An asterisk will be displayed next to the name of queries that have gone parallel. - - Added a check for parallel plans. - - Added @results parameter - options are 'narrow', 'simple', and 'expert' - - Added a check for plans using a downlevel cardinality estimator - - Added checks for plans with implicit conversions or plan affecting convert warnings - - Added check for queries with spill warnings - - Consolidated warning detection into a smaller number of T-SQL statements - - Added a Warnings column - - Added "busy loops" check - - Fixed bug where long-running query threshold was 300 microseconds, not seconds - -v2.0 - 2014-03-23 - - Created a stored procedure - - Added write information - - Added option to export to a single table - - Corrected accidental exclusion of trigger information - -v1.4 - 2014-02-17 - - MOAR BUG FIXES - - Corrected multiple sorting bugs that cause confusing displays of query - results that weren't necessarily the top anything. - - Updated all modification timestamps to use ISO 8601 formatting because it's - correct, sorry Britain. - - Added a check for SQL Server 2008R2 build greater than SP1. - Thanks to Kevan Riley for spotting this. - - Added the stored procedure or trigger name to the Query Type column. - Initial suggestion from Kevan Riley. - - Corrected erronous math that could allow for % CPU/Duration/Executions/Reads - being higher than 100% for batches/procedures with multiple poorly - performing statements in them. - -v1.3 - 2014-02-06 - - As they say on the app store, "Bug fixes" - - Reorganized this to put the standard, gotta-run stuff at the top. - - Switched to YYYY/MM/DD because Brits. - -v1.2 - 2014-02-04 -- Removed debug code -- Fixed output where SQL Server 2008 and early don't support min_rows, - max_rows, and total_rows. - SQL Server 2008 and earlier will now return NULL for those columns. - -v1.1 - 2014-02-02 -- Incorporated sys.dm_exec_plan_attributes as recommended by Andrey - and Michael J. Swart. -- Added additional detail columns for plan cache analysis including - min/max rows, total rows. -- Streamlined collection of data. - - - -*******************************************/ -AS -SET NOCOUNT ON; -SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED; - -DECLARE @nl nvarchar(2) = NCHAR(13) + NCHAR(10) ; - -IF @get_help = 1 -BEGIN - SELECT N'@get_help' AS [Parameter Name] , - N'BIT' AS [Data Type] , - N'Displays this help message.' AS [Parameter Description] - - UNION ALL - SELECT N'@top', - N'INT', - N'The number of records to retrieve and analyze from the plan cache. The following DMVs are used as the plan cache: dm_exec_query_stats, dm_exec_procedure_stats, dm_exec_trigger_stats.' - - UNION ALL - SELECT N'@sort_order', - N'VARCHAR(10)', - N'Data processing and display order. @sort_order will still be used, even when preparing output for a table or for excel. Possible values are: "CPU", "Reads", "Writes", "Duration", "Executions". Additionally, the word "Average" or "Avg" can be used to sort on averages rather than total. "Executions per minute" and "Executions / minute" can be used to sort by execution per minute. For the truly lazy, "xpm" can also be used.' - - UNION ALL - SELECT N'@use_triggers_anyway', - N'BIT', - N'On SQL Server 2008R2 and earlier, trigger execution count is incorrect - trigger execution count is incremented once per execution of a SQL agent job. If you still want to see relative execution count of triggers, then you can force sp_BlitzCache to include this information.' - - UNION ALL - SELECT N'@export_to_excel', - N'BIT', - N'Prepare output for exporting to Excel. Newlines and additional whitespace are removed from query text and the execution plan is not displayed.' - - UNION ALL - SELECT N'@results', - N'VARCHAR(10)', - N'Results mode. Options are "Narrow", "Simple", or "Expert". This determines which columns will be displayed in the analysis of the plan cache.' - - UNION ALL - SELECT N'@output_database_name', - N'NVARCHAR(128)', - N'The output database. If this does not exist SQL Server will divide by zero and everything will fall apart.' - - UNION ALL - SELECT N'@output_schema_name', - N'NVARCHAR(256)', - N'The output schema. If this does not exist SQL Server will divide by zero and everything will fall apart.' - - UNION ALL - SELECT N'@output_table_name', - N'NVARCHAR(256)', - N'The output table. If this does not exist, it will be created for you.' - - UNION ALL - SELECT N'@duration_filter', - N'DECIMAL(38,4)', - N'Excludes queries with an average duration (in seconds) less than @duration_filter.' - - UNION ALL - SELECT N'@hide_summary', - N'BIT', - N'Hides the findings summary result set.' - - UNION ALL - SELECT N'@ignore_system_db', - N'BIT', - N'Ignores plans found in the system databases (master, model, msdb, tempdb, and resourcedb)' - - UNION ALL - SELECT N'@only_query_hashes', - N'VARCHAR(MAX)', - N'A list of query hashes to query. All other query hashes will be ignored. Stored procedures and triggers will be ignored.' - - UNION ALL - SELECT N'@ignore_query_hashes', - N'VARCHAR(MAX)', - N'A list of query hashes to ignore.' - - UNION ALL - SELECT N'@whole_cache', - N'BIT', - N'This forces sp_BlitzCache to examine the entire plan cache. Be careful running this on servers with a lot of memory or a large execution plan cache.' - - UNION ALL - SELECT N'@query_filter', - N'VARCHAR(10)', - N'Filter out stored procedures or statements. The default value is ''ALL''. Allowed values are ''procedures'', ''statements'', or ''all'' (any variation in capitalization is acceptable).' - - UNION ALL - SELECT N'@reanalyze', - N'BIT', - N'The default is 0. When set to 0, sp_BlitzCache will re-evalute the plan cache. Set this to 1 to reanalyze existing results'; - - - - /* Column definitions */ - SELECT N'# Executions' AS [Column Name], - N'BIGINT' AS [Data Type], - N'The number of executions of this particular query. This is computed across statements, procedures, and triggers and aggregated by the SQL handle.' AS [Column Description] - - UNION ALL - SELECT N'Executions / Minute', - N'MONEY', - N'Number of executions per minute - calculated for the life of the current plan. Plan life is the last execution time minus the plan creation time.' - - UNION ALL - SELECT N'Execution Weight', - N'MONEY', - N'An arbitrary metric of total "execution-ness". A weight of 2 is "one more" than a weight of 1.' - - UNION ALL - SELECT N'Database', - N'sysname', - N'The name of the database where the plan was encountered. If the database name cannot be determined for some reason, a value of NA will be substituted. A value of 32767 indicates the plan comes from ResourceDB.' - - UNION ALL - SELECT N'Total CPU', - N'BIGINT', - N'Total CPU time, reported in milliseconds, that was consumed by all executions of this query since the last compilation.' - - UNION ALL - SELECT N'Avg CPU', - N'BIGINT', - N'Average CPU time, reported in milliseconds, consumed by each execution of this query since the last compilation.' - - UNION ALL - SELECT N'CPU Weight', - N'MONEY', - N'An arbitrary metric of total "CPU-ness". A weight of 2 is "one more" than a weight of 1.' - - - UNION ALL - SELECT N'Total Duration', - N'BIGINT', - N'Total elapsed time, reported in milliseconds, consumed by all executions of this query since last compilation.' - - UNION ALL - SELECT N'Avg Duration', - N'BIGINT', - N'Average elapsed time, reported in milliseconds, consumed by each execution of this query since the last compilation.' - - UNION ALL - SELECT N'Duration Weight', - N'MONEY', - N'An arbitrary metric of total "Duration-ness". A weight of 2 is "one more" than a weight of 1.' - - UNION ALL - SELECT N'Total Reads', - N'BIGINT', - N'Total logical reads performed by this query since last compilation.' - - UNION ALL - SELECT N'Average Reads', - N'BIGINT', - N'Average logical reads performed by each execution of this query since the last compilation.' - - UNION ALL - SELECT N'Read Weight', - N'MONEY', - N'An arbitrary metric of "Read-ness". A weight of 2 is "one more" than a weight of 1.' - - UNION ALL - SELECT N'Total Writes', - N'BIGINT', - N'Total logical writes performed by this query since last compilation.' - - UNION ALL - SELECT N'Average Writes', - N'BIGINT', - N'Average logical writes performed by each execution this query since last compilation.' - - UNION ALL - SELECT N'Write Weight', - N'MONEY', - N'An arbitrary metric of "Write-ness". A weight of 2 is "one more" than a weight of 1.' - - UNION ALL - SELECT N'Query Type', - N'NVARCHAR(256)', - N'The type of query being examined. This can be "Procedure", "Statement", or "Trigger".' - - UNION ALL - SELECT N'Query Text', - N'NVARCHAR(4000)', - N'The text of the query. This may be truncated by either SQL Server or by sp_BlitzCache(tm) for display purposes.' - - UNION ALL - SELECT N'% Executions (Type)', - N'MONEY', - N'Percent of executions relative to the type of query - e.g. 17.2% of all stored procedure executions.' - - UNION ALL - SELECT N'% CPU (Type)', - N'MONEY', - N'Percent of CPU time consumed by this query for a given type of query - e.g. 22% of CPU of all stored procedures executed.' - - UNION ALL - SELECT N'% Duration (Type)', - N'MONEY', - N'Percent of elapsed time consumed by this query for a given type of query - e.g. 12% of all statements executed.' - - UNION ALL - SELECT N'% Reads (Type)', - N'MONEY', - N'Percent of reads consumed by this query for a given type of query - e.g. 34.2% of all stored procedures executed.' - - UNION ALL - SELECT N'% Writes (Type)', - N'MONEY', - N'Percent of writes performed by this query for a given type of query - e.g. 43.2% of all statements executed.' - - UNION ALL - SELECT N'Total Rows', - N'BIGINT', - N'Total number of rows returned for all executions of this query. This only applies to query level stats, not stored procedures or triggers.' - - UNION ALL - SELECT N'Average Rows', - N'MONEY', - N'Average number of rows returned by each execution of the query.' - - UNION ALL - SELECT N'Min Rows', - N'BIGINT', - N'The minimum number of rows returned by any execution of this query.' - - UNION ALL - SELECT N'Max Rows', - N'BIGINT', - N'The maximum number of rows returned by any execution of this query.' - - UNION ALL - SELECT N'# Plans', - N'INT', - N'The total number of execution plans found that match a given query.' - - UNION ALL - SELECT N'# Distinct Plans', - N'INT', - N'The number of distinct execution plans that match a given query. ' - + NCHAR(13) + NCHAR(10) - + N'This may be caused by running the same query across multiple databases or because of a lack of proper parameterization in the database.' - - UNION ALL - SELECT N'Created At', - N'DATETIME', - N'Time that the execution plan was last compiled.' - - UNION ALL - SELECT N'Last Execution', - N'DATETIME', - N'The last time that this query was executed.' - - UNION ALL - SELECT N'Query Plan', - N'XML', - N'The query plan. Click to display a graphical plan or, if you need to patch SSMS, a pile of XML.' - - UNION ALL - SELECT N'Plan Handle', - N'VARBINARY(64)', - N'An arbitrary identifier referring to the compiled plan this query is a part of.' - - UNION ALL - SELECT N'SQL Handle', - N'VARBINARY(64)', - N'An arbitrary identifier referring to a batch or stored procedure that this query is a part of.' - - UNION ALL - SELECT N'Query Hash', - N'BINARY(8)', - N'A hash of the query. Queries with the same query hash have similar logic but only differ by literal values or database.' - - UNION ALL - SELECT N'Warnings', - N'VARCHAR(MAX)', - N'A list of individual warnings generated by this query.' ; - - - - /* Configuration table description */ - SELECT N'Frequent Execution Threshold' AS [Configuration Parameter] , - N'100' AS [Default Value] , - N'Executions / Minute' AS [Unit of Measure] , - N'Executions / Minute before a "Frequent Execution Threshold" warning is triggered.' AS [Description] - - UNION ALL - SELECT N'Parameter Sniffing Variance Percent' , - N'30' , - N'Percent' , - N'Variance required between min/max values and average values before a "Parameter Sniffing" warning is triggered. Applies to worker time and returned rows.' - - UNION ALL - SELECT N'Parameter Sniffing IO Threshold' , - N'100,000' , - N'Logical reads' , - N'Minimum number of average logical reads before parameter sniffing checks are evaluated.' - - UNION ALL - SELECT N'Cost Threshold for Parallelism Warning' AS [Configuration Parameter] , - N'10' , - N'Percent' , - N'Trigger a "Nearly Parallel" warning when a query''s cost is within X percent of the cost threshold for parallelism.' - - UNION ALL - SELECT N'Long Running Query Warning' AS [Configuration Parameter] , - N'300' , - N'Seconds' , - N'Triggers a "Long Running Query Warning" when average duration, max CPU time, or max clock time is higher than this number.' - - RETURN -END - -DECLARE @duration_filter_i INT, - @msg NVARCHAR(4000) ; - -RAISERROR (N'Setting up temporary tables for sp_BlitzCache',0,1) WITH NOWAIT; - -/* Change duration from seconds to milliseconds */ -IF @duration_filter IS NOT NULL - SET @duration_filter_i = CAST((@duration_filter * 1000.0) AS INT) - -SET @sort_order = LOWER(@sort_order); -SET @sort_order = REPLACE(REPLACE(@sort_order, 'average', 'avg'), '.', ''); -SET @sort_order = REPLACE(@sort_order, 'executions per minute', 'avg executions'); -SET @sort_order = REPLACE(@sort_order, 'executions / minute', 'avg executions'); -SET @sort_order = REPLACE(@sort_order, 'xpm', 'avg executions'); - - -IF @sort_order NOT IN ('cpu', 'avg cpu', 'reads', 'avg reads', 'writes', 'avg writes', - 'duration', 'avg duration', 'executions', 'avg executions') - SET @sort_order = 'cpu'; - -SELECT @output_database_name = QUOTENAME(@output_database_name), - @output_schema_name = QUOTENAME(@output_schema_name), - @output_table_name = QUOTENAME(@output_table_name); - -SET @query_filter = LOWER(@query_filter); - -IF LEFT(@query_filter, 3) NOT IN ('all', 'sta', 'pro') - SET @query_filter = 'all'; - -IF @reanalyze = 1 - GOTO Results - - -IF OBJECT_ID('tempdb..#only_query_hashes') IS NOT NULL - DROP TABLE #only_query_hashes ; - -IF OBJECT_ID('tempdb..#ignore_query_hashes') IS NOT NULL - DROP TABLE #ignore_query_hashes ; - -IF OBJECT_ID('tempdb..##bou_BlitzCacheResults') IS NOT NULL - DROP TABLE ##bou_BlitzCacheResults; - -IF OBJECT_ID('tempdb..#p') IS NOT NULL - DROP TABLE #p; - -IF OBJECT_ID('tempdb..##bou_BlitzCacheProcs') IS NOT NULL - DROP TABLE ##bou_BlitzCacheProcs; - -IF OBJECT_ID ('tempdb..#checkversion') IS NOT NULL - DROP TABLE #checkversion; - -IF OBJECT_ID ('tempdb..#configuration') IS NOT NULL - DROP TABLE #configuration; - -CREATE TABLE #only_query_hashes ( - query_hash BINARY(8) -); - -CREATE TABLE #ignore_query_hashes ( - query_hash BINARY(8) -); - -CREATE TABLE ##bou_BlitzCacheResults ( - ID INT IDENTITY(1,1), - CheckID INT, - Priority TINYINT, - FindingsGroup VARCHAR(50), - Finding VARCHAR(200), - URL VARCHAR(200), - Details VARCHAR(4000) -); - -CREATE TABLE #p ( - SqlHandle varbinary(64), - TotalCPU bigint, - TotalDuration bigint, - TotalReads bigint, - TotalWrites bigint, - ExecutionCount bigint -); - -CREATE TABLE #checkversion ( - version nvarchar(128), - maj_version AS SUBSTRING(version, 1,CHARINDEX('.', version) + 1 ), - build AS PARSENAME(CONVERT(varchar(32), version), 2) -); - -CREATE TABLE #configuration ( - parameter_name VARCHAR(100), - value DECIMAL(38,0) -); - -CREATE TABLE ##bou_BlitzCacheProcs ( - QueryType nvarchar(256), - DatabaseName sysname, - AverageCPU decimal(38,4), - AverageCPUPerMinute decimal(38,4), - TotalCPU decimal(38,4), - PercentCPUByType money, - PercentCPU money, - AverageDuration decimal(38,4), - TotalDuration decimal(38,4), - PercentDuration money, - PercentDurationByType money, - AverageReads bigint, - TotalReads bigint, - PercentReads money, - PercentReadsByType money, - ExecutionCount bigint, - PercentExecutions money, - PercentExecutionsByType money, - ExecutionsPerMinute money, - TotalWrites bigint, - AverageWrites money, - PercentWrites money, - PercentWritesByType money, - WritesPerMinute money, - PlanCreationTime datetime, - LastExecutionTime datetime, - PlanHandle varbinary(64), - SqlHandle varbinary(64), - QueryHash binary(8), - QueryPlanHash binary(8), - StatementStartOffset int, - StatementEndOffset int, - MinReturnedRows bigint, - MaxReturnedRows bigint, - AverageReturnedRows money, - TotalReturnedRows bigint, - LastReturnedRows bigint, - QueryText nvarchar(max), - QueryPlan xml, - /* these next four columns are the total for the type of query. - don't actually use them for anything apart from math by type. - */ - TotalWorkerTimeForType bigint, - TotalElapsedTimeForType bigint, - TotalReadsForType bigint, - TotalExecutionCountForType bigint, - TotalWritesForType bigint, - NumberOfPlans int, - NumberOfDistinctPlans int, - min_worker_time bigint, - max_worker_time bigint, - is_forced_plan bit, - is_forced_parameterized bit, - is_cursor bit, - is_parallel bit, - frequent_execution bit, - parameter_sniffing bit, - unparameterized_query bit, - near_parallel bit, - plan_warnings bit, - plan_multiple_plans bit, - long_running bit, - downlevel_estimator bit, - implicit_conversions bit, - tempdb_spill bit, - busy_loops bit, - tvf_join bit, - tvf_estimate bit, - compile_timeout bit, - compile_memory_limit_exceeded bit, - warning_no_join_predicate bit, - QueryPlanCost float, - missing_index_count int, - unmatched_index_count int, - min_elapsed_time bigint, - max_elapsed_time bigint, - age_minutes money, - age_minutes_lifetime money, - is_trivial bit, - SetOptions VARCHAR(MAX), - Warnings VARCHAR(MAX) -); - -SET @only_query_hashes = LTRIM(RTRIM(@only_query_hashes)) ; -SET @ignore_query_hashes = LTRIM(RTRIM(@ignore_query_hashes)) ; - -IF ((@only_query_hashes IS NOT NULL AND LEN(@only_query_hashes) > 0) - OR (@ignore_query_hashes IS NOT NULL AND LEN(@ignore_query_hashes) > 0)) - AND LEFT(@query_filter, 3) = 'pro' -BEGIN - RAISERROR('You cannot limit by query hash and filter by stored procedure', 16, 1); - RETURN; -END - -/* If the user is attempting to limit by query hash, set up the - #only_query_hashes temp table. This will be used to narrow down - results. - - Just a reminder: Using @only_query_hashes will ignore stored - procedures and triggers. - */ -IF @only_query_hashes IS NOT NULL - AND LEN(@only_query_hashes) > 0 -BEGIN - DECLARE @individual VARCHAR(50) ; - - WHILE LEN(@only_query_hashes) > 0 - BEGIN - IF PATINDEX('%,%', @only_query_hashes) > 0 - BEGIN - SET @individual = SUBSTRING(@only_query_hashes, 0, PATINDEX('%,%',@only_query_hashes)) ; - - INSERT INTO #only_query_hashes - select cast('' as xml).value('xs:hexBinary( substring(sql:variable("@individual"), sql:column("t.pos")) )', 'varbinary(max)') - from (select case substring(@individual, 1, 2) when '0x' then 3 else 0 end) as t(pos) - - --SELECT CAST(SUBSTRING(@individual, 1, 2) AS BINARY(8)); - - SET @only_query_hashes = SUBSTRING(@only_query_hashes, LEN(@individual + ',') + 1, LEN(@only_query_hashes)) ; - END - ELSE - BEGIN - SET @individual = @only_query_hashes - SET @only_query_hashes = NULL - - INSERT INTO #only_query_hashes - select cast('' as xml).value('xs:hexBinary( substring(sql:variable("@individual"), sql:column("t.pos")) )', 'varbinary(max)') - from (select case substring(@individual, 1, 2) when '0x' then 3 else 0 end) as t(pos) - - --SELECT CAST(SUBSTRING(@individual, 1, 2) AS VARBINARY(MAX)) ; - END - END -END - -/* If the user is setting up a list of query hashes to ignore, those - values will be inserted into #ignore_query_hashes. This is used to - exclude values from query results. - - Stored procedures and triggers will still be queried. - */ -IF @ignore_query_hashes IS NOT NULL - AND LEN(@ignore_query_hashes) > 0 -BEGIN - SET @individual = '' ; - - WHILE LEN(@ignore_query_hashes) > 0 - BEGIN - IF PATINDEX('%,%', @ignore_query_hashes) > 0 - BEGIN - SET @individual = SUBSTRING(@ignore_query_hashes, 0, PATINDEX('%,%',@ignore_query_hashes)) ; - - INSERT INTO #ignore_query_hashes - SELECT CAST('' AS XML).value('xs:hexBinary( substring(sql:variable("@individual"), sql:column("t.pos")) )', 'varbinary(max)') - FROM (SELECT CASE SUBSTRING(@individual, 1, 2) WHEN '0x' THEN 3 ELSE 0 END) AS t(pos) ; - - SET @ignore_query_hashes = SUBSTRING(@ignore_query_hashes, LEN(@individual + ',') + 1, LEN(@ignore_query_hashes)) ; - END - ELSE - BEGIN - SET @individual = @ignore_query_hashes ; - SET @ignore_query_hashes = NULL ; - - INSERT INTO #ignore_query_hashes - SELECT CAST('' AS XML).value('xs:hexBinary( substring(sql:variable("@individual"), sql:column("t.pos")) )', 'varbinary(max)') - FROM (SELECT CASE SUBSTRING(@individual, 1, 2) WHEN '0x' THEN 3 ELSE 0 END) AS t(pos) ; - END - END -END - -IF @configuration_database_name IS NOT NULL -BEGIN - DECLARE @config_sql NVARCHAR(MAX) = N'INSERT INTO #configuration SELECT parameter_name, value FROM ' - + QUOTENAME(@configuration_database_name) - + '.' + QUOTENAME(@configuration_schema_name) - + '.' + QUOTENAME(@configuration_table_name) - + ' ; ' ; - EXEC(@config_sql); -END - -DECLARE @sql nvarchar(MAX) = N'', - @insert_list nvarchar(MAX) = N'', - @plans_triggers_select_list nvarchar(MAX) = N'', - @body nvarchar(MAX) = N'', - @body_where nvarchar(MAX) = N'', - @body_order nvarchar(MAX) = N'ORDER BY #sortable# DESC OPTION (RECOMPILE) ', - - @q nvarchar(1) = N'''', - @pv varchar(20), - @pos tinyint, - @v decimal(6,2), - @build int; - - -RAISERROR (N'Determining SQL Server version.',0,1) WITH NOWAIT; - -INSERT INTO #checkversion (version) -SELECT CAST(SERVERPROPERTY('ProductVersion') as nvarchar(128)) -OPTION (RECOMPILE); - - -SELECT @v = maj_version , - @build = build -FROM #checkversion -OPTION (RECOMPILE); - -RAISERROR (N'Creating dynamic SQL based on SQL Server version.',0,1) WITH NOWAIT; - -SET @insert_list += N' -INSERT INTO ##bou_BlitzCacheProcs (QueryType, DatabaseName, AverageCPU, TotalCPU, AverageCPUPerMinute, PercentCPUByType, PercentDurationByType, - PercentReadsByType, PercentExecutionsByType, AverageDuration, TotalDuration, AverageReads, TotalReads, ExecutionCount, - ExecutionsPerMinute, TotalWrites, AverageWrites, PercentWritesByType, WritesPerMinute, PlanCreationTime, - LastExecutionTime, StatementStartOffset, StatementEndOffset, MinReturnedRows, MaxReturnedRows, AverageReturnedRows, TotalReturnedRows, - LastReturnedRows, QueryText, QueryPlan, TotalWorkerTimeForType, TotalElapsedTimeForType, TotalReadsForType, - TotalExecutionCountForType, TotalWritesForType, SqlHandle, PlanHandle, QueryHash, QueryPlanHash, - min_worker_time, max_worker_time, is_parallel, min_elapsed_time, max_elapsed_time, age_minutes, age_minutes_lifetime) ' ; - -SET @body += N' -FROM (SELECT *, - CAST((CASE WHEN DATEDIFF(second, cached_time, GETDATE()) > 0 AND execution_count > 1 - THEN DATEDIFF(second, cached_time, GETDATE()) / 60.0 - ELSE NULL END) as MONEY) as age_minutes, - CAST((CASE WHEN DATEDIFF(second, cached_time, last_execution_time) > 0 AND execution_count > 1 - THEN DATEDIFF(second, cached_time, last_execution_time) / 60.0 - ELSE Null END) as MONEY) as age_minutes_lifetime - FROM sys.#view# x ' + @nl ; - -IF (SELECT COUNT(*) FROM #only_query_hashes) > 0 - AND (SELECT COUNT(*) FROM #ignore_query_hashes) = 0 -BEGIN - SET @body += N' WHERE EXISTS(SELECT 1/0 FROM #only_query_hashes q WHERE q.query_hash = x.query_hash) ' + @nl -END - - -SET @body += N') AS qs - CROSS JOIN(SELECT SUM(execution_count) AS t_TotalExecs, - SUM(total_elapsed_time) / 1000.0 AS t_TotalElapsed, - SUM(total_worker_time) / 1000.0 AS t_TotalWorker, - SUM(total_logical_reads) AS t_TotalReads, - SUM(total_logical_writes) AS t_TotalWrites - FROM sys.#view#) AS t - CROSS APPLY sys.dm_exec_plan_attributes(qs.plan_handle) AS pa - CROSS APPLY sys.dm_exec_sql_text(qs.sql_handle) AS st - CROSS APPLY sys.dm_exec_query_plan(qs.plan_handle) AS qp ' + @nl ; - -SET @body_where = N'WHERE pa.attribute = ' + QUOTENAME('dbid', @q) + @nl ; - -IF @duration_filter IS NOT NULL - SET @body_where += N' AND (total_elapsed_time / 1000.0) / execution_count > @min_duration ' + @nl ; - -SET @plans_triggers_select_list += N' -SELECT TOP (@top) - ''Procedure: '' + COALESCE(OBJECT_NAME(qs.object_id, qs.database_id),'''') AS QueryType, - COALESCE(DB_NAME(database_id), CAST(pa.value AS sysname), ''-- N/A --'') AS DatabaseName, - (total_worker_time / 1000.0) / execution_count AS AvgCPU , - (total_worker_time / 1000.0) AS TotalCPU , - CASE WHEN total_worker_time = 0 THEN 0 - WHEN COALESCE(age_minutes, DATEDIFF(mi, qs.cached_time, qs.last_execution_time), 0) = 0 THEN 0 - ELSE CAST((total_worker_time / 1000.0) / COALESCE(age_minutes, DATEDIFF(mi, qs.cached_time, qs.last_execution_time)) AS MONEY) - END AS AverageCPUPerMinute , - CASE WHEN t.t_TotalWorker = 0 THEN 0 - ELSE CAST(ROUND(100.00 * (total_worker_time / 1000.0) / t.t_TotalWorker, 2) AS MONEY) - END AS PercentCPUByType, - CASE WHEN t.t_TotalElapsed = 0 THEN 0 - ELSE CAST(ROUND(100.00 * (total_elapsed_time / 1000.0) / t.t_TotalElapsed, 2) AS MONEY) - END AS PercentDurationByType, - CASE WHEN t.t_TotalReads = 0 THEN 0 - ELSE CAST(ROUND(100.00 * total_logical_reads / t.t_TotalReads, 2) AS MONEY) - END AS PercentReadsByType, - CASE WHEN t.t_TotalExecs = 0 THEN 0 - ELSE CAST(ROUND(100.00 * execution_count / t.t_TotalExecs, 2) AS MONEY) - END AS PercentExecutionsByType, - (total_elapsed_time / 1000.0) / execution_count AS AvgDuration , - (total_elapsed_time / 1000.0) AS TotalDuration , - total_logical_reads / execution_count AS AvgReads , - total_logical_reads AS TotalReads , - execution_count AS ExecutionCount , - CASE WHEN execution_count = 0 THEN 0 - WHEN COALESCE(age_minutes, DATEDIFF(mi, qs.cached_time, qs.last_execution_time), 0) = 0 THEN 0 - ELSE CAST((1.00 * execution_count / COALESCE(age_minutes, DATEDIFF(mi, qs.cached_time, qs.last_execution_time))) AS money) - END AS ExecutionsPerMinute , - total_logical_writes AS TotalWrites , - total_logical_writes / execution_count AS AverageWrites , - CASE WHEN t.t_TotalWrites = 0 THEN 0 - ELSE CAST(ROUND(100.00 * total_logical_writes / t.t_TotalWrites, 2) AS MONEY) - END AS PercentWritesByType, - CASE WHEN total_logical_writes = 0 THEN 0 - WHEN COALESCE(age_minutes, DATEDIFF(mi, qs.cached_time, qs.last_execution_time), 0) = 0 THEN 0 - ELSE CAST((1.00 * total_logical_writes / COALESCE(age_minutes, DATEDIFF(mi, qs.cached_time, qs.last_execution_time), 0)) AS money) - END AS WritesPerMinute, - qs.cached_time AS PlanCreationTime, - qs.last_execution_time AS LastExecutionTime, - NULL AS StatementStartOffset, - NULL AS StatementEndOffset, - NULL AS MinReturnedRows, - NULL AS MaxReturnedRows, - NULL AS AvgReturnedRows, - NULL AS TotalReturnedRows, - NULL AS LastReturnedRows, - st.text AS QueryText , - query_plan AS QueryPlan, - t.t_TotalWorker, - t.t_TotalElapsed, - t.t_TotalReads, - t.t_TotalExecs, - t.t_TotalWrites, - qs.sql_handle AS SqlHandle, - qs.plan_handle AS PlanHandle, - NULL AS QueryHash, - NULL AS QueryPlanHash, - qs.min_worker_time / 1000.0, - qs.max_worker_time / 1000.0, - CASE WHEN qp.query_plan.value(''declare namespace p="http://schemas.microsoft.com/sqlserver/2004/07/showplan";max(//p:RelOp/@Parallel)'', ''float'') > 0 THEN 1 ELSE 0 END, - qs.min_elapsed_time / 1000.0, - qs.max_elapsed_time / 1000.0, - age_minutes, - age_minutes_lifetime ' - - -IF LEFT(@query_filter, 3) IN ('all', 'sta') -BEGIN - SET @sql += @insert_list; - - SET @sql += N' - SELECT TOP (@top) - ''Statement'' AS QueryType, - COALESCE(DB_NAME(CAST(pa.value AS INT)), ''-- N/A --'') AS DatabaseName, - (total_worker_time / 1000.0) / execution_count AS AvgCPU , - (total_worker_time / 1000.0) AS TotalCPU , - CASE WHEN total_worker_time = 0 THEN 0 - WHEN COALESCE(age_minutes, DATEDIFF(mi, qs.creation_time, qs.last_execution_time), 0) = 0 THEN 0 - ELSE CAST((total_worker_time / 1000.0) / COALESCE(age_minutes, DATEDIFF(mi, qs.creation_time, qs.last_execution_time)) AS MONEY) - END AS AverageCPUPerMinute , - CAST(ROUND(100.00 * (total_worker_time / 1000.0) / t.t_TotalWorker, 2) AS MONEY) AS PercentCPUByType, - CAST(ROUND(100.00 * (total_elapsed_time / 1000.0) / t.t_TotalElapsed, 2) AS MONEY) AS PercentDurationByType, - CAST(ROUND(100.00 * total_logical_reads / t.t_TotalReads, 2) AS MONEY) AS PercentReadsByType, - CAST(ROUND(100.00 * execution_count / t.t_TotalExecs, 2) AS MONEY) AS PercentExecutionsByType, - (total_elapsed_time / 1000.0) / execution_count AS AvgDuration , - (total_elapsed_time / 1000.0) AS TotalDuration , - total_logical_reads / execution_count AS AvgReads , - total_logical_reads AS TotalReads , - execution_count AS ExecutionCount , - CASE WHEN execution_count = 0 THEN 0 - WHEN COALESCE(age_minutes, DATEDIFF(mi, qs.creation_time, qs.last_execution_time), 0) = 0 THEN 0 - ELSE CAST((1.00 * execution_count / COALESCE(age_minutes, DATEDIFF(mi, qs.creation_time, qs.last_execution_time))) AS money) - END AS ExecutionsPerMinute , - total_logical_writes AS TotalWrites , - total_logical_writes / execution_count AS AverageWrites , - CASE WHEN t.t_TotalWrites = 0 THEN 0 - ELSE CAST(ROUND(100.00 * total_logical_writes / t.t_TotalWrites, 2) AS MONEY) - END AS PercentWritesByType, - CASE WHEN total_logical_writes = 0 THEN 0 - WHEN COALESCE(age_minutes, DATEDIFF(mi, qs.creation_time, qs.last_execution_time), 0) = 0 THEN 0 - ELSE CAST((1.00 * total_logical_writes / COALESCE(age_minutes, DATEDIFF(mi, qs.creation_time, qs.last_execution_time), 0)) AS money) - END AS WritesPerMinute, - qs.creation_time AS PlanCreationTime, - qs.last_execution_time AS LastExecutionTime, - qs.statement_start_offset AS StatementStartOffset, - qs.statement_end_offset AS StatementEndOffset, ' - - IF (@v >= 11) OR (@v >= 10.5 AND @build >= 2500) - BEGIN - SET @sql += N' - qs.min_rows AS MinReturnedRows, - qs.max_rows AS MaxReturnedRows, - CAST(qs.total_rows as MONEY) / execution_count AS AvgReturnedRows, - qs.total_rows AS TotalReturnedRows, - qs.last_rows AS LastReturnedRows, ' ; - END - ELSE - BEGIN - SET @sql += N' - NULL AS MinReturnedRows, - NULL AS MaxReturnedRows, - NULL AS AvgReturnedRows, - NULL AS TotalReturnedRows, - NULL AS LastReturnedRows, ' ; - END - - SET @sql += N' - SUBSTRING(st.text, ( qs.statement_start_offset / 2 ) + 1, ( ( CASE qs.statement_end_offset - WHEN -1 THEN DATALENGTH(st.text) - ELSE qs.statement_end_offset - END - qs.statement_start_offset ) / 2 ) + 1) AS QueryText , - query_plan AS QueryPlan, - t.t_TotalWorker, - t.t_TotalElapsed, - t.t_TotalReads, - t.t_TotalExecs, - t.t_TotalWrites, - qs.sql_handle AS SqlHandle, - NULL AS PlanHandle, - qs.query_hash AS QueryHash, - qs.query_plan_hash AS QueryPlanHash, - qs.min_worker_time / 1000.0, - qs.max_worker_time / 1000.0, - CASE WHEN qp.query_plan.value(''declare namespace p="http://schemas.microsoft.com/sqlserver/2004/07/showplan";max(//p:RelOp/@Parallel)'', ''float'') > 0 THEN 1 ELSE 0 END, - qs.min_elapsed_time / 1000.0, - qs.max_worker_time / 1000.0, - age_minutes, - age_minutes_lifetime ' - - SET @sql += REPLACE(REPLACE(@body, '#view#', 'dm_exec_query_stats'), 'cached_time', 'creation_time') ; - - IF (SELECT COUNT(*) FROM #ignore_query_hashes) > 0 - AND (SELECT COUNT(*) FROM #only_query_hashes) = 0 - BEGIN - SET @sql += REPLACE(@sql, ') AS qs', ') AS qs - LEFT JOIN #ignore_query_hashes iqh ON iqh.query_hash = qs.query_hash ' + @nl) ; - END - - - - - SET @sql += @body_where ; - - IF @ignore_system_db = 1 - SET @sql += 'AND COALESCE(DB_NAME(CAST(pa.value AS INT)), '''') NOT IN (''master'', ''model'', ''msdb'', ''tempdb'', ''32767'') ' + @nl ; - - IF (SELECT COUNT(*) FROM #ignore_query_hashes) > 0 - AND (SELECT COUNT(*) FROM #only_query_hashes) = 0 - BEGIN - SET @sql += ' AND iqh.query_hash IS NULL ' + @nl ; - END - - SET @sql += @body_order + @nl + @nl + @nl; -END - - -IF (@query_filter = 'all' AND (SELECT COUNT(*) FROM #only_query_hashes) = 0) - OR (LEFT(@query_filter, 3) = 'pro') -BEGIN - SET @sql += @insert_list; - SET @sql += REPLACE(@plans_triggers_select_list, '#query_type#', 'Stored Procedure') ; - - SET @sql += REPLACE(@body, '#view#', 'dm_exec_procedure_stats') ; - SET @sql += @body_where ; - - IF @ignore_system_db = 1 - SET @sql += ' AND COALESCE(DB_NAME(database_id), CAST(pa.value AS sysname), '''') NOT IN (''master'', ''model'', ''msdb'', ''tempdb'', ''32767'') ' + @nl ; - - SET @sql += @body_order + @nl + @nl + @nl ; -END - - - -/******************************************************************************* - * - * Because the trigger execution count in SQL Server 2008R2 and earlier is not - * correct, we ignore triggers for these versions of SQL Server. If you'd like - * to include trigger numbers, just know that the ExecutionCount, - * PercentExecutions, and ExecutionsPerMinute are wildly inaccurate for - * triggers on these versions of SQL Server. - * - * This is why we can't have nice things. - * - ******************************************************************************/ -IF (@use_triggers_anyway = 1 OR @v >= 11) - AND (SELECT COUNT(*) FROM #only_query_hashes) = 0 - AND (@query_filter = 'all') -BEGIN - RAISERROR (N'Adding SQL to collect trigger stats.',0,1) WITH NOWAIT; - - /* Trigger level information from the plan cache */ - SET @sql += @insert_list ; - - SET @sql += REPLACE(@plans_triggers_select_list, '#query_type#', 'Trigger') ; - - SET @sql += REPLACE(@body, '#view#', 'dm_exec_trigger_stats') ; - - SET @sql += @body_where ; - - IF @ignore_system_db = 1 - SET @sql += ' AND COALESCE(DB_NAME(database_id), CAST(pa.value AS sysname), '''') NOT IN (''master'', ''model'', ''msdb'', ''tempdb'', ''32767'') ' + @nl ; -END - - - - -DECLARE @sort NVARCHAR(MAX); - -SELECT @sort = CASE @sort_order WHEN 'cpu' THEN 'total_worker_time' - WHEN 'reads' THEN 'total_logical_reads' - WHEN 'writes' THEN 'total_logical_writes' - WHEN 'duration' THEN 'total_elapsed_time' - WHEN 'executions' THEN 'execution_count' - /* And now the averages */ - WHEN 'avg cpu' THEN 'total_worker_time / execution_count' - WHEN 'avg reads' THEN 'total_logical_reads / execution_count' - WHEN 'avg writes' THEN 'total_logical_writes / execution_count' - WHEN 'avg duration' THEN 'total_elapsed_time / execution_count' - WHEN 'avg executions' THEN 'CASE WHEN execution_count = 0 THEN 0 - WHEN COALESCE(age_minutes, age_minutes_lifetime, 0) = 0 THEN 0 - ELSE CAST((1.00 * execution_count / COALESCE(age_minutes, age_minutes_lifetime)) AS money) - END' - END ; - -SELECT @sql = REPLACE(@sql, '#sortable#', @sort); - -SET @sql += N' -INSERT INTO #p (SqlHandle, TotalCPU, TotalReads, TotalDuration, TotalWrites, ExecutionCount) -SELECT SqlHandle, - TotalCPU, - TotalReads, - TotalDuration, - TotalWrites, - ExecutionCount -FROM (SELECT SqlHandle, - TotalCPU, - TotalReads, - TotalDuration, - TotalWrites, - ExecutionCount, - ROW_NUMBER() OVER (PARTITION BY SqlHandle ORDER BY #sortable# DESC) AS rn - FROM ##bou_BlitzCacheProcs) AS x -WHERE x.rn = 1 -OPTION (RECOMPILE); -'; - -SELECT @sort = CASE @sort_order WHEN 'cpu' THEN 'TotalCPU' - WHEN 'reads' THEN 'TotalReads' - WHEN 'writes' THEN 'TotalWrites' - WHEN 'duration' THEN 'TotalDuration' - WHEN 'executions' THEN 'ExecutionCount' - WHEN 'avg cpu' THEN 'TotalCPU / ExecutionCount' - WHEN 'avg reads' THEN 'TotalReads / ExecutionCount' - WHEN 'avg writes' THEN 'TotalWrites / ExecutionCount' - WHEN 'avg duration' THEN 'TotalDuration / ExecutionCount' - WHEN 'avg executions' THEN 'CASE WHEN ExecutionCount = 0 THEN 0 - WHEN COALESCE(age_minutes, age_minutes_lifetime, 0) = 0 THEN 0 - ELSE CAST((1.00 * ExecutionCount / COALESCE(age_minutes, age_minutes_lifetime)) AS money) - END' - END ; - -SELECT @sql = REPLACE(@sql, '#sortable#', @sort); - - -IF @reanalyze = 0 -BEGIN - RAISERROR('Collecting execution plan information.', 0, 1) WITH NOWAIT; - - EXEC sp_executesql @sql, N'@top INT, @min_duration INT', @top, @duration_filter_i; -END - - - -/* Compute the total CPU, etc across our active set of the plan cache. - * Yes, there's a flaw - this doesn't include anything outside of our @top - * metric. - */ -RAISERROR('Computing CPU, duration, read, and write metrics', 0, 1) WITH NOWAIT; -DECLARE @total_duration BIGINT, - @total_cpu BIGINT, - @total_reads BIGINT, - @total_writes BIGINT, - @total_execution_count BIGINT; - -SELECT @total_cpu = SUM(TotalCPU), - @total_duration = SUM(TotalDuration), - @total_reads = SUM(TotalReads), - @total_writes = SUM(TotalWrites), - @total_execution_count = SUM(ExecutionCount) -FROM #p -OPTION (RECOMPILE) ; - -DECLARE @cr NVARCHAR(1) = NCHAR(13); -DECLARE @lf NVARCHAR(1) = NCHAR(10); -DECLARE @tab NVARCHAR(1) = NCHAR(9); - -/* Update CPU percentage for stored procedures */ -UPDATE ##bou_BlitzCacheProcs -SET PercentCPU = y.PercentCPU, - PercentDuration = y.PercentDuration, - PercentReads = y.PercentReads, - PercentWrites = y.PercentWrites, - PercentExecutions = y.PercentExecutions, - ExecutionsPerMinute = y.ExecutionsPerMinute, - /* Strip newlines and tabs. Tabs are replaced with multiple spaces - so that the later whitespace trim will completely eliminate them - */ - QueryText = REPLACE(REPLACE(REPLACE(QueryText, @cr, ' '), @lf, ' '), @tab, ' ') -FROM ( - SELECT PlanHandle, - CASE @total_cpu WHEN 0 THEN 0 - ELSE CAST((100. * TotalCPU) / @total_cpu AS MONEY) END AS PercentCPU, - CASE @total_duration WHEN 0 THEN 0 - ELSE CAST((100. * TotalDuration) / @total_duration AS MONEY) END AS PercentDuration, - CASE @total_reads WHEN 0 THEN 0 - ELSE CAST((100. * TotalReads) / @total_reads AS MONEY) END AS PercentReads, - CASE @total_writes WHEN 0 THEN 0 - ELSE CAST((100. * TotalWrites) / @total_writes AS MONEY) END AS PercentWrites, - CASE @total_execution_count WHEN 0 THEN 0 - ELSE CAST((100. * ExecutionCount) / @total_execution_count AS MONEY) END AS PercentExecutions, - CASE DATEDIFF(mi, PlanCreationTime, LastExecutionTime) - WHEN 0 THEN 0 - ELSE CAST((1.00 * ExecutionCount / DATEDIFF(mi, PlanCreationTime, LastExecutionTime)) AS money) - END AS ExecutionsPerMinute - FROM ( - SELECT PlanHandle, - TotalCPU, - TotalDuration, - TotalReads, - TotalWrites, - ExecutionCount, - PlanCreationTime, - LastExecutionTime - FROM ##bou_BlitzCacheProcs - WHERE PlanHandle IS NOT NULL - GROUP BY PlanHandle, - TotalCPU, - TotalDuration, - TotalReads, - TotalWrites, - ExecutionCount, - PlanCreationTime, - LastExecutionTime - ) AS x -) AS y -WHERE ##bou_BlitzCacheProcs.PlanHandle = y.PlanHandle - AND ##bou_BlitzCacheProcs.PlanHandle IS NOT NULL -OPTION (RECOMPILE) ; - - - -UPDATE ##bou_BlitzCacheProcs -SET PercentCPU = y.PercentCPU, - PercentDuration = y.PercentDuration, - PercentReads = y.PercentReads, - PercentWrites = y.PercentWrites, - PercentExecutions = y.PercentExecutions, - ExecutionsPerMinute = y.ExecutionsPerMinute, - /* Strip newlines and tabs. Tabs are replaced with multiple spaces - so that the later whitespace trim will completely eliminate them - */ - QueryText = REPLACE(REPLACE(REPLACE(QueryText, @cr, ' '), @lf, ' '), @tab, ' ') -FROM ( - SELECT DatabaseName, - SqlHandle, - QueryHash, - CASE @total_cpu WHEN 0 THEN 0 - ELSE CAST((100. * TotalCPU) / @total_cpu AS MONEY) END AS PercentCPU, - CASE @total_duration WHEN 0 THEN 0 - ELSE CAST((100. * TotalDuration) / @total_duration AS MONEY) END AS PercentDuration, - CASE @total_reads WHEN 0 THEN 0 - ELSE CAST((100. * TotalReads) / @total_reads AS MONEY) END AS PercentReads, - CASE @total_writes WHEN 0 THEN 0 - ELSE CAST((100. * TotalWrites) / @total_writes AS MONEY) END AS PercentWrites, - CASE @total_execution_count WHEN 0 THEN 0 - ELSE CAST((100. * ExecutionCount) / @total_execution_count AS MONEY) END AS PercentExecutions, - CASE DATEDIFF(mi, PlanCreationTime, LastExecutionTime) - WHEN 0 THEN 0 - ELSE CAST((1.00 * ExecutionCount / DATEDIFF(mi, PlanCreationTime, LastExecutionTime)) AS money) - END AS ExecutionsPerMinute - FROM ( - SELECT DatabaseName, - SqlHandle, - QueryHash, - TotalCPU, - TotalDuration, - TotalReads, - TotalWrites, - ExecutionCount, - PlanCreationTime, - LastExecutionTime - FROM ##bou_BlitzCacheProcs - GROUP BY DatabaseName, - SqlHandle, - QueryHash, - TotalCPU, - TotalDuration, - TotalReads, - TotalWrites, - ExecutionCount, - PlanCreationTime, - LastExecutionTime - ) AS x -) AS y -WHERE ##bou_BlitzCacheProcs.SqlHandle = y.SqlHandle - AND ##bou_BlitzCacheProcs.QueryHash = y.QueryHash - AND ##bou_BlitzCacheProcs.DatabaseName = y.DatabaseName - AND ##bou_BlitzCacheProcs.PlanHandle IS NULL -OPTION (RECOMPILE) ; - - - -WITH XMLNAMESPACES('http://schemas.microsoft.com/sqlserver/2004/07/showplan' AS p) -UPDATE ##bou_BlitzCacheProcs -SET NumberOfDistinctPlans = distinct_plan_count, - NumberOfPlans = number_of_plans, - QueryPlanCost = CASE WHEN QueryType LIKE '%Stored Procedure%' THEN - QueryPlan.value('sum(//p:StmtSimple/@StatementSubTreeCost)', 'float') - ELSE - QueryPlan.value('sum(//p:StmtSimple[xs:hexBinary(substring(@QueryPlanHash, 3)) = xs:hexBinary(sql:column("QueryPlanHash"))]/@StatementSubTreeCost)', 'float') - END, - missing_index_count = QueryPlan.value('count(//p:MissingIndexGroup)', 'int') , - unmatched_index_count = QueryPlan.value('count(//p:UnmatchedIndexes/p:Parameterization/p:Object)', 'int') , - plan_multiple_plans = CASE WHEN distinct_plan_count < number_of_plans THEN 1 END , - is_trivial = CASE WHEN QueryPlan.exist('//p:StmtSimple[@StatementOptmLevel[.="TRIVIAL"]]/p:QueryPlan/p:ParameterList') = 1 THEN 1 END -FROM ( -SELECT COUNT(DISTINCT QueryHash) AS distinct_plan_count, - COUNT(QueryHash) AS number_of_plans, - QueryHash -FROM ##bou_BlitzCacheProcs -GROUP BY QueryHash -) AS x -WHERE ##bou_BlitzCacheProcs.QueryHash = x.QueryHash -OPTION (RECOMPILE) ; - - - -/* Set configuration values */ -DECLARE @execution_threshold INT = 1000 , - @parameter_sniffing_warning_pct TINYINT = 30, - /* This is in average reads */ - @parameter_sniffing_io_threshold BIGINT = 100000 , - @ctp_threshold_pct TINYINT = 10, - @long_running_query_warning_seconds BIGINT = 300 * 1000 ; - -IF EXISTS (SELECT 1/0 FROM #configuration WHERE 'frequent execution threshold' = LOWER(parameter_name)) -BEGIN - SELECT @execution_threshold = CAST(value AS INT) - FROM #configuration - WHERE 'frequent execution threshold' = LOWER(parameter_name) ; - - SET @msg = ' Setting "frequent execution threshold" to ' + CAST(@execution_threshold AS VARCHAR(10)) ; - - RAISERROR(@msg, 0, 1) WITH NOWAIT; -END - -IF EXISTS (SELECT 1/0 FROM #configuration WHERE 'parameter sniffing variance percent' = LOWER(parameter_name)) -BEGIN - SELECT @parameter_sniffing_warning_pct = CAST(value AS TINYINT) - FROM #configuration - WHERE 'parameter sniffing variance percent' = LOWER(parameter_name) ; - - SET @msg = ' Setting "parameter sniffing variance percent" to ' + CAST(@parameter_sniffing_warning_pct AS VARCHAR(3)) ; - - RAISERROR(@msg, 0, 1) WITH NOWAIT; -END - -IF EXISTS (SELECT 1/0 FROM #configuration WHERE 'parameter sniffing io threshold' = LOWER(parameter_name)) -BEGIN - SELECT @parameter_sniffing_io_threshold = CAST(value AS BIGINT) - FROM #configuration - WHERE 'parameter sniffing io threshold' = LOWER(parameter_name) ; - - SET @msg = ' Setting "parameter sniffing io threshold" to ' + CAST(@parameter_sniffing_io_threshold AS VARCHAR(10)); - - RAISERROR(@msg, 0, 1) WITH NOWAIT; -END - -IF EXISTS (SELECT 1/0 FROM #configuration WHERE 'cost threshold for parallelism warning' = LOWER(parameter_name)) -BEGIN - SELECT @ctp_threshold_pct = CAST(value AS TINYINT) - FROM #configuration - WHERE 'cost threshold for parallelism warning' = LOWER(parameter_name) ; - - SET @msg = ' Setting "cost threshold for parallelism warning" to ' + CAST(@ctp_threshold_pct AS VARCHAR(3)); - - RAISERROR(@msg, 0, 1) WITH NOWAIT; -END - -IF EXISTS (SELECT 1/0 FROM #configuration WHERE 'long running query warning (seconds)' = LOWER(parameter_name)) -BEGIN - SELECT @long_running_query_warning_seconds = CAST(value * 1000 AS BIGINT) - FROM #configuration - WHERE 'long running query warning (seconds)' = LOWER(parameter_name) ; - - SET @msg = ' Setting "long running query warning (seconds)" to ' + CAST(@long_running_query_warning_seconds AS VARCHAR(10)); - - RAISERROR(@msg, 0, 1) WITH NOWAIT; -END - -DECLARE @ctp INT ; - -SELECT @ctp = CAST(value AS INT) -FROM sys.configurations -WHERE name = 'cost threshold for parallelism' -OPTION (RECOMPILE); - - - -/* Update to populate checks columns */ -RAISERROR('Checking for query level SQL Server issues.', 0, 1) WITH NOWAIT; - -WITH XMLNAMESPACES('http://schemas.microsoft.com/sqlserver/2004/07/showplan' AS p) -UPDATE ##bou_BlitzCacheProcs -SET frequent_execution = CASE WHEN ExecutionsPerMinute > @execution_threshold THEN 1 END , - parameter_sniffing = CASE WHEN AverageReads > @parameter_sniffing_io_threshold - AND min_worker_time < ((1.0 - (@parameter_sniffing_warning_pct / 100.0)) * AverageCPU) THEN 1 - WHEN AverageReads > @parameter_sniffing_io_threshold - AND max_worker_time > ((1.0 + (@parameter_sniffing_warning_pct / 100.0)) * AverageCPU) THEN 1 - WHEN AverageReads > @parameter_sniffing_io_threshold - AND MinReturnedRows < ((1.0 - (@parameter_sniffing_warning_pct / 100.0)) * AverageReturnedRows) THEN 1 - WHEN AverageReads > @parameter_sniffing_io_threshold - AND MaxReturnedRows > ((1.0 + (@parameter_sniffing_warning_pct / 100.0)) * AverageReturnedRows) THEN 1 END , - near_parallel = CASE WHEN QueryPlanCost BETWEEN @ctp * (1 - (@ctp_threshold_pct / 100.0)) AND @ctp THEN 1 END, - plan_warnings = CASE WHEN QueryPlan.value('count(//p:Warnings)', 'int') > 0 THEN 1 END, - long_running = CASE WHEN AverageDuration > @long_running_query_warning_seconds THEN 1 - WHEN max_worker_time > @long_running_query_warning_seconds THEN 1 - WHEN max_elapsed_time > @long_running_query_warning_seconds THEN 1 END , - implicit_conversions = CASE WHEN QueryPlan.exist(' - //p:PlanAffectingConvert/@Expression - [contains(., "CONVERT_IMPLICIT")]') = 1 THEN 1 - END , - tempdb_spill = CASE WHEN QueryPlan.value('max(//p:SpillToTempDb/@SpillLevel)', 'int') > 0 THEN 1 END , - unparameterized_query = CASE WHEN QueryPlan.exist('//p:StmtSimple[@StatementOptmLevel[.="FULL"]]/p:QueryPlan/p:ParameterList') = 1 AND - QueryPlan.exist('//p:StmtSimple[@StatementOptmLevel[.="FULL"]]/p:QueryPlan/p:ParameterList/p:ColumnReference') = 0 THEN 1 - WHEN QueryPlan.exist('//p:StmtSimple[@StatementOptmLevel[.="FULL"]]/p:QueryPlan/p:ParameterList') = 0 AND - QueryPlan.exist('//p:StmtSimple[@StatementOptmLevel[.="FULL"]]/*/p:RelOp/descendant::p:ScalarOperator/p:Identifier/p:ColumnReference[contains(@Column, "@")]') - = 1 THEN 1 END ; - - - -/* Checks that require examining individual plan nodes, as opposed to - the entire plan - */ -RAISERROR('Scanning individual plan nodes for query issues.', 0, 1) WITH NOWAIT; - -WITH XMLNAMESPACES('http://schemas.microsoft.com/sqlserver/2004/07/showplan' AS p) -UPDATE p -SET busy_loops = CASE WHEN (x.estimated_executions / 100.0) > x.estimated_rows THEN 1 END , - tvf_join = CASE WHEN x.tvf_join = 1 THEN 1 END , - warning_no_join_predicate = CASE WHEN x.no_join_warning = 1 THEN 1 END -FROM ##bou_BlitzCacheProcs p - JOIN ( - SELECT qs.SqlHandle, - n.value('@EstimateRows', 'float') AS estimated_rows , - n.value('@EstimateRewinds', 'float') + n.value('@EstimateRebinds', 'float') + 1.0 AS estimated_executions , - n.query('.').exist('/p:RelOp[contains(@LogicalOp, "Join")]/*/p:RelOp[(@LogicalOp[.="Table-valued function"])]') AS tvf_join, - n.query('.').exist('//p:RelOp/p:Warnings[(@NoJoinPredicate[.="1"])]') AS no_join_warning - FROM ##bou_BlitzCacheProcs qs - OUTER APPLY qs.QueryPlan.nodes('//p:RelOp') AS q(n) - ) AS x ON p.SqlHandle = x.SqlHandle ; - - - -/* Check for timeout plan termination */ -RAISERROR('Checking for plan compilation timeouts.', 0, 1) WITH NOWAIT; - -WITH XMLNAMESPACES('http://schemas.microsoft.com/sqlserver/2004/07/showplan' AS p) -UPDATE p -SET compile_timeout = CASE WHEN n.query('.').exist('/p:StmtSimple/@StatementOptmEarlyAbortReason[.="TimeOut"]') = 1 THEN 1 END , - compile_memory_limit_exceeded = CASE WHEN n.query('.').exist('/p:StmtSimple/@StatementOptmEarlyAbortReason[.="MemoryLimitExceeded"]') = 1 THEN 1 END -FROM ##bou_BlitzCacheProcs p - CROSS APPLY p.QueryPlan.nodes('//p:StmtSimple') AS q(n) ; - - - -RAISERROR('Checking for forced parameterization and cursors.', 0, 1) WITH NOWAIT; - -/* Set options checks */ -UPDATE p -SET is_forced_parameterized = CASE WHEN (CAST(pa.value AS INT) & 131072 = 131072) THEN 1 - END , - is_forced_plan = CASE WHEN (CAST(pa.value AS INT) & 131072 = 131072) THEN 1 - WHEN (CAST(pa.value AS INT) & 4 = 4) THEN 1 - END , - SetOptions = SUBSTRING( - CASE WHEN (CAST(pa.value AS INT) & 1 = 1) THEN ', ANSI_PADDING' ELSE '' END + - CASE WHEN (CAST(pa.value AS INT) & 8 = 8) THEN ', CONCAT_NULL_YIELDS_NULL' ELSE '' END + - CASE WHEN (CAST(pa.value AS INT) & 16 = 16) THEN ', ANSI_WARNINGS' ELSE '' END + - CASE WHEN (CAST(pa.value AS INT) & 32 = 32) THEN ', ANSI_NULLS' ELSE '' END + - CASE WHEN (CAST(pa.value AS INT) & 64 = 64) THEN ', QUOTED_IDENTIFIER' ELSE '' END + - CASE WHEN (CAST(pa.value AS INT) & 4096 = 4096) THEN ', ARITH_ABORT' ELSE '' END + - CASE WHEN (CAST(pa.value AS INT) & 8192 = 8191) THEN ', NUMERIC_ROUNDABORT' ELSE '' END - , 2, 200000) -FROM ##bou_BlitzCacheProcs p - CROSS APPLY sys.dm_exec_plan_attributes(p.PlanHandle) pa -WHERE pa.attribute = 'set_options' ; - - - -/* Cursor checks */ -UPDATE p -SET is_cursor = CASE WHEN CAST(pa.value AS INT) <> 0 THEN 1 END -FROM ##bou_BlitzCacheProcs p - CROSS APPLY sys.dm_exec_plan_attributes(p.PlanHandle) pa -WHERE pa.attribute LIKE '%cursor%' ; - - - -/* Downlevel cardinality estimator */ -IF @v >= 12 -BEGIN - RAISERROR('Checking for downlevel cardinality estimators being used on SQL Server 2014.', 0, 1) WITH NOWAIT; - - WITH XMLNAMESPACES('http://schemas.microsoft.com/sqlserver/2004/07/showplan' AS p) - UPDATE ##bou_BlitzCacheProcs - SET downlevel_estimator = CASE WHEN QueryPlan.value('min(//p:StmtSimple/@CardinalityEstimationModelVersion)', 'int') < (@v * 10) THEN 1 END ; -END - - - -RAISERROR('Populating Warnings column', 0, 1) WITH NOWAIT; - -/* Populate warnings */ -UPDATE ##bou_BlitzCacheProcs -SET Warnings = SUBSTRING( - CASE WHEN warning_no_join_predicate = 1 THEN ', No Join Predicate' ELSE '' END + - CASE WHEN compile_timeout = 1 THEN ', Compilation Timeout' ELSE '' END + - CASE WHEN compile_memory_limit_exceeded = 1 THEN ', Compile Memory Limit Exceeded' ELSE '' END + - CASE WHEN busy_loops = 1 THEN ', Busy Loops' ELSE '' END + - CASE WHEN is_forced_plan = 1 THEN ', Forced Plan' ELSE '' END + - CASE WHEN is_forced_parameterized = 1 THEN ', Forced Parameterization' ELSE '' END + - CASE WHEN unparameterized_query = 1 THEN ', Unparameterized Query' ELSE '' END + - CASE WHEN missing_index_count > 0 THEN ', Missing Indexes (' + CAST(missing_index_count AS VARCHAR(3)) + ')' ELSE '' END + - CASE WHEN unmatched_index_count > 0 THEN ', Unmatched Indexes (' + CAST(unmatched_index_count AS VARCHAR(3)) + ')' ELSE '' END + - CASE WHEN is_cursor = 1 THEN ', Cursor' ELSE '' END + - CASE WHEN is_parallel = 1 THEN ', Parallel' ELSE '' END + - CASE WHEN near_parallel = 1 THEN ', Nearly Parallel' ELSE '' END + - CASE WHEN frequent_execution = 1 THEN ', Frequent Execution' ELSE '' END + - CASE WHEN plan_warnings = 1 THEN ', Plan Warnings' ELSE '' END + - CASE WHEN parameter_sniffing = 1 THEN ', Parameter Sniffing' ELSE '' END + - CASE WHEN long_running = 1 THEN ', Long Running Query' ELSE '' END + - CASE WHEN downlevel_estimator = 1 THEN ', Downlevel CE' ELSE '' END + - CASE WHEN implicit_conversions = 1 THEN ', Implicit Conversions' ELSE '' END + - CASE WHEN tempdb_spill = 1 THEN ', TempDB Spills' ELSE '' END + - CASE WHEN tvf_join = 1 THEN ', Function Join' ELSE '' END + - CASE WHEN plan_multiple_plans = 1 THEN ', Multiple Plans' ELSE '' END + - CASE WHEN is_trivial = 1 THEN ', Trivial Plans' ELSE '' END - , 2, 200000) ; - - - - - - - - - - - - -Results: -IF @output_database_name IS NOT NULL - AND @output_schema_name IS NOT NULL - AND @output_table_name IS NOT NULL -BEGIN - RAISERROR('Writing results to table.', 0, 1) WITH NOWAIT; - - /* send results to a table */ - DECLARE @insert_sql NVARCHAR(MAX) = N'' ; - - SET @insert_sql = 'USE ' - + @output_database_name - + '; IF EXISTS(SELECT * FROM ' - + @output_database_name - + '.INFORMATION_SCHEMA.SCHEMATA WHERE QUOTENAME(SCHEMA_NAME) = ''' - + @output_schema_name - + ''') AND NOT EXISTS (SELECT * FROM ' - + @output_database_name - + '.INFORMATION_SCHEMA.TABLES WHERE QUOTENAME(TABLE_SCHEMA) = ''' - + @output_schema_name + ''' AND QUOTENAME(TABLE_NAME) = ''' - + @output_table_name + ''') CREATE TABLE ' - + @output_schema_name + '.' - + @output_table_name - + N'(ID bigint NOT NULL IDENTITY(1,1), - ServerName nvarchar(256), - Version nvarchar(256), - QueryType nvarchar(256), - Warnings varchar(max), - DatabaseName sysname, - AverageCPU bigint, - TotalCPU bigint, - PercentCPUByType money, - CPUWeight money, - AverageDuration bigint, - TotalDuration bigint, - DurationWeight money, - PercentDurationByType money, - AverageReads bigint, - TotalReads bigint, - ReadWeight money, - PercentReadsByType money, - AverageWrites bigint, - TotalWrites bigint, - WriteWeight money, - PercentWritesByType money, - ExecutionCount bigint, - ExecutionWeight money, - PercentExecutionsByType money,' + N' - ExecutionsPerMinute money, - PlanCreationTime datetime, - LastExecutionTime datetime, - PlanHandle varbinary(64), - SqlHandle varbinary(64), - QueryHash binary(8), - StatementStartOffset int, - StatementEndOffset int, - MinReturnedRows bigint, - MaxReturnedRows bigint, - AverageReturnedRows money, - TotalReturnedRows bigint, - QueryText nvarchar(max), - QueryPlan xml, - NumberOfPlans int, - NumberOfDistinctPlans int, - SampleTime DATETIME DEFAULT(GETDATE()) - CONSTRAINT [PK_' +CAST(NEWID() AS NCHAR(36)) + '] PRIMARY KEY CLUSTERED(ID))'; - - EXEC sp_executesql @insert_sql ; - - SET @insert_sql =N' IF EXISTS(SELECT * FROM ' - + @output_database_name - + N'.INFORMATION_SCHEMA.SCHEMATA WHERE QUOTENAME(SCHEMA_NAME) = ''' - + @output_schema_name + N''') ' - + 'INSERT ' - + @output_database_name + '.' - + @output_schema_name + '.' - + @output_table_name - + N' (ServerName, Version, QueryType, DatabaseName, AverageCPU, TotalCPU, PercentCPUByType, CPUWeight, AverageDuration, TotalDuration, DurationWeight, PercentDurationByType, AverageReads, TotalReads, ReadWeight, PercentReadsByType, ' - + N' AverageWrites, TotalWrites, WriteWeight, PercentWritesByType, ExecutionCount, ExecutionWeight, PercentExecutionsByType, ' - + N' ExecutionsPerMinute, PlanCreationTime, LastExecutionTime, PlanHandle, SqlHandle, QueryHash, StatementStartOffset, StatementEndOffset, MinReturnedRows, MaxReturnedRows, AverageReturnedRows, TotalReturnedRows, QueryText, QueryPlan, NumberOfPlans, NumberOfDistinctPlans, Warnings) ' - + N'SELECT TOP (@top) ' - + QUOTENAME(CAST(SERVERPROPERTY('ServerName') AS NVARCHAR(128)), N'''') + N', ' - + QUOTENAME(CAST(SERVERPROPERTY('ProductVersion') as nvarchar(128)), N'''') + ', ' - + N' QueryType, DatabaseName, AverageCPU, TotalCPU, PercentCPUByType, PercentCPU, AverageDuration, TotalDuration, PercentDuration, PercentDurationByType, AverageReads, TotalReads, PercentReads, PercentReadsByType, ' - + N' AverageWrites, TotalWrites, PercentWrites, PercentWritesByType, ExecutionCount, PercentExecutions, PercentExecutionsByType, ' - + N' ExecutionsPerMinute, PlanCreationTime, LastExecutionTime, PlanHandle, SqlHandle, QueryHash, StatementStartOffset, StatementEndOffset, MinReturnedRows, MaxReturnedRows, AverageReturnedRows, TotalReturnedRows, QueryText, QueryPlan, NumberOfPlans, NumberOfDistinctPlans, Warnings ' - + N' FROM ##bou_BlitzCacheProcs ' - - SELECT @insert_sql += N' ORDER BY ' + CASE @sort_order WHEN 'cpu' THEN ' TotalCPU ' - WHEN 'reads' THEN ' TotalReads ' - WHEN 'writes' THEN ' TotalWrites ' - WHEN 'duration' THEN ' TotalDuration ' - WHEN 'executions' THEN ' ExecutionCount ' - WHEN 'avg cpu' THEN 'AverageCPU' - WHEN 'avg reads' THEN 'AverageReads' - WHEN 'avg writes' THEN 'AverageWrites' - WHEN 'avg duration' THEN 'AverageDuration' - WHEN 'avg executions' THEN 'ExecutionsPerMinute' - END + N' DESC ' - - SET @insert_sql += N' OPTION (RECOMPILE) ; ' - - EXEC sp_executesql @insert_sql, N'@top INT', @top; - - RETURN -END -ELSE IF @export_to_excel = 1 -BEGIN - RAISERROR('Displaying results with Excel formatting (no plans).', 0, 1) WITH NOWAIT; - - /* excel output */ - UPDATE ##bou_BlitzCacheProcs - SET QueryText = SUBSTRING(REPLACE(REPLACE(REPLACE(LTRIM(RTRIM(QueryText)),' ','<>'),'><',''),'<>',' '), 1, 32000); - - SET @sql = N' - SELECT TOP (@top) - DatabaseName AS [Database Name], - QueryPlanCost AS [Cost], - QueryText, - QueryType AS [Query Type], - Warnings, - ExecutionCount, - ExecutionsPerMinute AS [Executions / Minute], - PercentExecutions AS [Execution Weight], - PercentExecutionsByType AS [% Executions (Type)], - TotalCPU AS [Total CPU (ms)], - AverageCPU AS [Avg CPU (ms)], - PercentCPU AS [CPU Weight], - PercentCPUByType AS [% CPU (Type)], - TotalDuration AS [Total Duration (ms)], - AverageDuration AS [Avg Duration (ms)], - PercentDuration AS [Duration Weight], - PercentDurationByType AS [% Duration (Type)], - TotalReads AS [Total Reads], - AverageReads AS [Average Reads], - PercentReads AS [Read Weight], - PercentReadsByType AS [% Reads (Type)], - TotalWrites AS [Total Writes], - AverageWrites AS [Average Writes], - PercentWrites AS [Write Weight], - PercentWritesByType AS [% Writes (Type)], - TotalReturnedRows, - AverageReturnedRows, - MinReturnedRows, - MaxReturnedRows, - NumberOfPlans, - NumberOfDistinctPlans, - PlanCreationTime AS [Created At], - LastExecutionTime AS [Last Execution], - StatementStartOffset, - StatementEndOffset, - COALESCE(SetOptions, '''') AS [SET Options] - FROM ##bou_BlitzCacheProcs - WHERE 1 = 1 ' + @nl - - SELECT @sql += N' ORDER BY ' + CASE @sort_order WHEN 'cpu' THEN ' TotalCPU ' - WHEN 'reads' THEN ' TotalReads ' - WHEN 'writes' THEN ' TotalWrites ' - WHEN 'duration' THEN ' TotalDuration ' - WHEN 'executions' THEN ' ExecutionCount ' - WHEN 'avg cpu' THEN 'AverageCPU' - WHEN 'avg reads' THEN 'AverageReads' - WHEN 'avg writes' THEN 'AverageWrites' - WHEN 'avg duration' THEN 'AverageDuration' - WHEN 'avg executions' THEN 'ExecutionsPerMinute' - END + N' DESC ' - - SET @sql += N' OPTION (RECOMPILE) ; ' - - EXEC sp_executesql @sql, N'@top INT', @top ; -END - -IF @hide_summary = 0 -BEGIN - IF @reanalyze = 0 - BEGIN - RAISERROR('Building query plan summary data.', 0, 1) WITH NOWAIT; - - /* Build summary data */ - IF EXISTS (SELECT 1/0 - FROM ##bou_BlitzCacheProcs - WHERE frequent_execution =1) - INSERT INTO ##bou_BlitzCacheResults (CheckID, Priority, FindingsGroup, Finding, URL, Details) - VALUES (1, - 100, - 'Execution Pattern', - 'Frequently Executed Queries', - 'http://brentozar.com/blitzcache/frequently-executed-queries/', - 'Queries are being executed more than ' - + CAST (@execution_threshold AS VARCHAR(5)) - + ' times per minute. This can put additional load on the server, even when queries are lightweight.') ; - - IF EXISTS (SELECT 1/0 - FROM ##bou_BlitzCacheProcs - WHERE parameter_sniffing = 1 - ) - INSERT INTO ##bou_BlitzCacheResults (CheckID, Priority, FindingsGroup, Finding, URL, Details) - VALUES (2, - 50, - 'Parameterization', - 'Parameter Sniffing', - 'http://brentozar.com/blitzcache/parameter-sniffing/', - 'There are signs of parameter sniffing (wide variance in rows return or time to execute). Investigate query patterns and tune code appropriately.') ; - - /* Forced execution plans */ - IF EXISTS (SELECT 1/0 - FROM ##bou_BlitzCacheProcs - WHERE is_forced_plan = 1 - ) - INSERT INTO ##bou_BlitzCacheResults (CheckID, Priority, FindingsGroup, Finding, URL, Details) - VALUES (3, - 5, - 'Parameterization', - 'Forced Plans', - 'http://brentozar.com/blitzcache/forced-plans/', - 'Execution plans have been compiled with forced plans, either through FORCEPLAN, plan guides, or forced parameterization. This will make general tuning efforts less effective.'); - - /* Cursors */ - IF EXISTS (SELECT 1/0 - FROM ##bou_BlitzCacheProcs - WHERE is_cursor = 1 - ) - INSERT INTO ##bou_BlitzCacheResults (CheckID, Priority, FindingsGroup, Finding, URL, Details) - VALUES (4, - 200, - 'Cursors', - 'Cursors', - 'http://brentozar.com/blitzcache/cursors-found-slow-queries/', - 'There are cursors in the plan cache. This is neither good nor bad, but it is a thing. Cursors are weird in SQL Server.'); - - IF EXISTS (SELECT 1/0 - FROM ##bou_BlitzCacheProcs - WHERE is_forced_parameterized = 1 - ) - INSERT INTO ##bou_BlitzCacheResults (CheckID, Priority, FindingsGroup, Finding, URL, Details) - VALUES (5, - 50, - 'Parameterization', - 'Forced Parameterization', - 'http://brentozar.com/blitzcache/forced-parameterization/', - 'Execution plans have been compiled with forced parameterization.') ; - - IF EXISTS (SELECT 1/0 - FROM ##bou_BlitzCacheProcs p - WHERE p.is_parallel = 1 - ) - INSERT INTO ##bou_BlitzCacheResults (CheckID, Priority, FindingsGroup, Finding, URL, Details) - VALUES (6, - 200, - 'Execution Plans', - 'Parallelism', - 'http://brentozar.com/blitzcache/parallel-plans-detected/', - 'Parallel plans detected. These warrant investigation, but are neither good nor bad.') ; - - IF EXISTS (SELECT 1/0 - FROM ##bou_BlitzCacheProcs p - WHERE near_parallel = 1 - ) - INSERT INTO ##bou_BlitzCacheResults (CheckID, Priority, FindingsGroup, Finding, URL, Details) - VALUES (7, - 200, - 'Execution Plans', - 'Nearly Parallel', - 'http://brentozar.com/blitzcache/query-cost-near-cost-threshold-parallelism/', - 'Queries near the cost threshold for parallelism. These may go parallel when you least expect it.') ; - - IF EXISTS (SELECT 1/0 - FROM ##bou_BlitzCacheProcs p - WHERE plan_warnings = 1 - ) - INSERT INTO ##bou_BlitzCacheResults (CheckID, Priority, FindingsGroup, Finding, URL, Details) - VALUES (8, - 50, - 'Execution Plans', - 'Query Plan Warnings', - 'http://brentozar.com/blitzcache/query-plan-warnings/', - 'Warnings detected in execution plans. SQL Server is telling you that something bad is going on that requires your attention.') ; - - IF EXISTS (SELECT 1/0 - FROM ##bou_BlitzCacheProcs p - WHERE long_running = 1 - ) - INSERT INTO ##bou_BlitzCacheResults (CheckID, Priority, FindingsGroup, Finding, URL, Details) - VALUES (9, - 50, - 'Performance', - 'Long Running Queries', - 'http://brentozar.com/blitzcache/long-running-queries/', - 'Long running queries have beend found. These are queries with an average duration longer than ' - + CAST(@long_running_query_warning_seconds / 1000 / 1000 AS VARCHAR(5)) - + ' second(s). These queries should be investigated for additional tuning options') ; - - IF EXISTS (SELECT 1/0 - FROM ##bou_BlitzCacheProcs p - WHERE p.missing_index_count > 0) - INSERT INTO ##bou_BlitzCacheResults (CheckID, Priority, FindingsGroup, Finding, URL, Details) - VALUES (10, - 50, - 'Performance', - 'Missing Index Request', - 'http://brentozar.com/blitzcache/missing-index-request/', - 'Queries found with missing indexes.'); - - IF EXISTS (SELECT 1/0 - FROM ##bou_BlitzCacheProcs p - WHERE p.downlevel_estimator = 1 - ) - INSERT INTO ##bou_BlitzCacheResults (CheckID, Priority, FindingsGroup, Finding, URL, Details) - VALUES (13, - 200, - 'Cardinality', - 'Legacy Cardinality Estimator in Use', - 'http://brentozar.com/blitzcache/legacy-cardinality-estimator/', - 'A legacy cardinality estimator is being used by one or more queries. Investigate whether you need to be using this cardinality estimator. This may be caused by compatibility levels, global trace flags, or query level trace flags.'); - - IF EXISTS (SELECT 1/0 - FROM ##bou_BlitzCacheProcs p - WHERE implicit_conversions = 1 - ) - INSERT INTO ##bou_BlitzCacheResults (CheckID, Priority, FindingsGroup, Finding, URL, Details) - VALUES (14, - 50, - 'Performance', - 'Implicit Conversions', - 'http://brentozar.com/go/implicit', - 'One or more queries are comparing two fields that are not of the same data type.') ; - - IF EXISTS (SELECT 1/0 - FROM ##bou_BlitzCacheProcs - WHERE tempdb_spill = 1 - ) - INSERT INTO ##bou_BlitzCacheResults (CheckID, Priority, FindingsGroup, Finding, URL, Details) - VALUES (15, - 10, - 'Performance', - 'TempDB Spills', - 'http://brentozar.com/blitzcache/tempdb-spills/', - 'TempDB spills detected. Queries are unable to allocate enough memory to proceed normally.'); - - IF EXISTS (SELECT 1/0 - FROM ##bou_BlitzCacheProcs - WHERE busy_loops = 1) - INSERT INTO ##bou_BlitzCacheResults (CheckID, Priority, FindingsGroup, Finding, URL, Details) - VALUES (16, - 10, - 'Performance', - 'Frequently executed operators', - 'http://brentozar.com/blitzcache/busy-loops/', - 'Operations have been found that are executed 100 times more often than the number of rows returned by each iteration. This is an indicator that something is off in query execution.'); - - IF EXISTS (SELECT 1/0 - FROM ##bou_BlitzCacheProcs - WHERE tvf_join = 1) - INSERT INTO ##bou_BlitzCacheResults (CheckID, Priority, FindingsGroup, Finding, URL, Details) - VALUES (17, - 50, - 'Performance', - 'Joining to table valued functions', - 'http://brentozar.com/blitzcache/tvf-join/', - 'Execution plans have been found that join to table valued functions (TVFs). TVFs produce inaccurate estimates of the number of rows returned and can lead to any number of query plan problems.'); - - IF EXISTS (SELECT 1/0 - FROM ##bou_BlitzCacheProcs - WHERE compile_timeout = 1) - INSERT INTO ##bou_BlitzCacheResults (CheckID, Priority, FindingsGroup, Finding, URL, Details) - VALUES (18, - 50, - 'Execution Plans', - 'Compilation timeout', - 'http://brentozar.com/blitzcache/compilation-timeout/', - 'Query compilation timed out for one or more queries. SQL Server did not find a plan that meets acceptable performance criteria in the time allotted so the best guess was returned. There is a very good chance that this plan isn''t even below average - it''s probably terrible.'); - - IF EXISTS (SELECT 1/0 - FROM ##bou_BlitzCacheProcs - WHERE compile_memory_limit_exceeded = 1) - INSERT INTO ##bou_BlitzCacheResults (CheckID, Priority, FindingsGroup, Finding, URL, Details) - VALUES (19, - 50, - 'Execution Plans', - 'Compilation memory limit exceeded', - 'http://brentozar.com/blitzcache/compile-memory-limit-exceeded/', - 'The optimizer has a limited amount of memory available. One or more queries are complex enough that SQL Server was unable to allocate enough memory to fully optimize the query. A best fit plan was found, and it''s probably terrible.'); - - IF EXISTS (SELECT 1/0 - FROM ##bou_BlitzCacheProcs - WHERE warning_no_join_predicate = 1) - INSERT INTO ##bou_BlitzCacheResults (CheckID, Priority, FindingsGroup, Finding, URL, Details) - VALUES (20, - 10, - 'Execution Plans', - 'No join predicate', - 'http://brentozar.com/blitzcache/no-join-predicate/', - 'Operators in a query have no join predicate. This means that all rows from one table will be matched with all rows from anther table producing a Cartesian product. That''s a whole lot of rows. This may be your goal, but it''s important to investigate why this is happening.'); - - IF EXISTS (SELECT 1/0 - FROM ##bou_BlitzCacheProcs - WHERE plan_multiple_plans = 1) - INSERT INTO ##bou_BlitzCacheResults (CheckID, Priority, FindingsGroup, Finding, URL, Details) - VALUES (21, - 200, - 'Execution Plans', - 'Multiple execution plans', - 'http://brentozar.com/blitzcache/multiple-plans/', - 'Queries exist with multiple execution plans (as determined by query_plan_hash). Investigate possible ways to parameterize these queries or otherwise reduce the plan count/'); - - IF EXISTS (SELECT 1/0 - FROM ##bou_BlitzCacheProcs - WHERE unmatched_index_count > 0) - INSERT INTO ##bou_BlitzCacheResults (CheckID, Priority, FindingsGroup, Finding, URL, Details) - VALUES (22, - 100, - 'Performance', - 'Unmatched indexes', - 'http://brentozar.com/blitzcache/unmatched-indexes', - 'An index could have been used, but SQL Server chose not to use it - likely due to parameterization and filtered indexes.'); - - IF EXISTS (SELECT 1/0 - FROM ##bou_BlitzCacheProcs - WHERE unparameterized_query = 1) - INSERT INTO ##bou_BlitzCacheResults (CheckID, Priority, FindingsGroup, Finding, URL, Details) - VALUES (23, - 100, - 'Parameterization', - 'Unparameterized queries', - 'http://brentozar.com/blitzcache/unparameterized-queries', - 'Unparameterized queries found. These could be ad hoc queries, data exploration, or queries using "OPTIMIZE FOR UNKNOWN".'); - - IF EXISTS (SELECT 1/0 - FROM ##bou_BlitzCacheProcs - WHERE is_trivial = 1) - INSERT INTO ##bou_BlitzCacheResults (CheckID, Priority, FindingsGroup, Finding, URL, Details) - VALUES (24, - 100, - 'Execution Plans', - 'Trivial Plans', - 'http://brentozar.com/blitzcache/trivial-plans', - 'Trivial plans get almost no optimization. If you''re finding these in the top worst queries, something may be going wrong.'); - END - - IF @export_to_excel = 1 - RETURN - - SELECT Priority, - FindingsGroup, - Finding, - URL, - Details, - CheckID - FROM ##bou_BlitzCacheResults - GROUP BY Priority, - FindingsGroup, - Finding, - URL, - Details, - CheckID - ORDER BY Priority ASC - OPTION (RECOMPILE); -END - - - -RAISERROR('Displaying analysis of plan cache.', 0, 1) WITH NOWAIT; - -DECLARE @columns NVARCHAR(MAX) = N'' ; - -IF LOWER(@results) = 'narrow' -BEGIN - SET @columns = N' DatabaseName AS [Database], - QueryPlanCost AS [Cost], - QueryText AS [Query Text], - QueryType AS [Query Type], - Warnings AS [Warnings], - ExecutionCount AS [# Executions], - AverageCPU AS [Average CPU (ms)], - AverageDuration AS [Average Duration (ms)], - AverageReads AS [Average Reads], - AverageWrites AS [Average Writes], - AverageReturnedRows AS [Average Rows Returned], - PlanCreationTime AS [Created At], - LastExecutionTime AS [Last Execution], - QueryPlan AS [Query] '; -END -ELSE IF LOWER(@results) = 'simple' -BEGIN - SET @columns = N' DatabaseName AS [Database], - QueryPlanCost AS [Cost], - QueryText AS [Query Text], - QueryType AS [Query Type], - Warnings AS [Warnings], - ExecutionCount AS [# Executions], - ExecutionsPerMinute AS [Executions / Minute], - PercentExecutions AS [Execution Weight], - TotalCPU AS [Total CPU (ms)], - AverageCPU AS [Avg CPU (ms)], - PercentCPU AS [CPU Weight], - TotalDuration AS [Total Duration (ms)], - AverageDuration AS [Avg Duration (ms)], - PercentDuration AS [Duration Weight], - TotalReads AS [Total Reads], - AverageReads AS [Avg Reads], - PercentReads AS [Read Weight], - TotalWrites AS [Total Writes], - AverageWrites AS [Avg Writes], - PercentWrites AS [Write Weight], - AverageReturnedRows AS [Average Rows], - PlanCreationTime AS [Created At], - LastExecutionTime AS [Last Execution], - QueryPlan AS [Query Plan], - COALESCE(SetOptions, '''') AS [SET Options] '; -END -ELSE -BEGIN - SET @columns = N' DatabaseName AS [Database], - QueryText AS [Query Text], - QueryType AS [Query Type], - Warnings AS [Warnings], ' + @nl - - IF LOWER(@results) = 'opserver1' - BEGIN - SET @columns += ' SUBSTRING( - CASE WHEN warning_no_join_predicate = 1 THEN '', 20'' ELSE '''' END + - CASE WHEN compile_timeout = 1 THEN '', 18'' ELSE '''' END + - CASE WHEN compile_memory_limit_exceeded = 1 THEN '', 19'' ELSE '''' END + - CASE WHEN busy_loops = 1 THEN '', 16'' ELSE '''' END + - CASE WHEN is_forced_plan = 1 THEN '', 3'' ELSE '''' END + - CASE WHEN is_forced_parameterized = 1 THEN '', 5'' ELSE '''' END + - CASE WHEN unparameterized_query = 1 THEN '', 23'' ELSE '''' END + - CASE WHEN missing_index_count > 0 THEN '', 10'' ELSE '''' END + - CASE WHEN unmatched_index_count > 0 THEN '', 22'' ELSE '''' END + - CASE WHEN is_cursor = 1 THEN '', 4'' ELSE '''' END + - CASE WHEN is_parallel = 1 THEN '', 6'' ELSE '''' END + - CASE WHEN near_parallel = 1 THEN '', 7'' ELSE '''' END + - CASE WHEN frequent_execution = 1 THEN '', 1'' ELSE '''' END + - CASE WHEN plan_warnings = 1 THEN '', 8'' ELSE '''' END + - CASE WHEN parameter_sniffing = 1 THEN '', 2'' ELSE '''' END + - CASE WHEN long_running = 1 THEN '', 9'' ELSE '''' END + - CASE WHEN downlevel_estimator = 1 THEN '', 13'' ELSE '''' END + - CASE WHEN implicit_conversions = 1 THEN '', 14'' ELSE '''' END + - CASE WHEN tempdb_spill = 1 THEN '', 15'' ELSE '''' END + - CASE WHEN tvf_join = 1 THEN '', 17'' ELSE '''' END + - CASE WHEN plan_multiple_plans = 1 THEN '', 21'' ELSE '''' END + - CASE WHEN unmatched_index_count > 0 THEN '', 22'', ELSE '''' END + - CASE WHEN unparameterized_query > 0 THEN '', 23'', ELSE '''' END + - Case WHEN is_trivial = 1 THEN '', 24'', ELSE '''' END - , 2, 200000) AS opserver_warning , ' + @nl ; - END - - SET @columns += N' ExecutionCount AS [# Executions], - ExecutionsPerMinute AS [Executions / Minute], - PercentExecutions AS [Execution Weight], - TotalCPU AS [Total CPU (ms)], - AverageCPU AS [Avg CPU (ms)], - PercentCPU AS [CPU Weight], - TotalDuration AS [Total Duration (ms)], - AverageDuration AS [Avg Duration (ms)], - PercentDuration AS [Duration Weight], - TotalReads AS [Total Reads], - AverageReads AS [Average Reads], - PercentReads AS [Read Weight], - TotalWrites AS [Total Writes], - AverageWrites AS [Average Writes], - PercentWrites AS [Write Weight], - PercentExecutionsByType AS [% Executions (Type)], - PercentCPUByType AS [% CPU (Type)], - PercentDurationByType AS [% Duration (Type)], - PercentReadsByType AS [% Reads (Type)], - PercentWritesByType AS [% Writes (Type)], - TotalReturnedRows AS [Total Rows], - AverageReturnedRows AS [Avg Rows], - MinReturnedRows AS [Min Rows], - MaxReturnedRows AS [Max Rows], - NumberOfPlans AS [# Plans], - NumberOfDistinctPlans AS [# Distinct Plans], - PlanCreationTime AS [Created At], - LastExecutionTime AS [Last Execution], - QueryPlanCost AS [Query Plan Cost], - QueryPlan AS [Query Plan], - COALESCE(SetOptions, '''') AS [SET Options], - PlanHandle AS [Plan Handle], - SqlHandle AS [SQL Handle], - QueryHash AS [Query Hash], - StatementStartOffset, - StatementEndOffset '; -END - - - -SET @sql = N' -SELECT TOP (@top) ' + @columns + @nl + N' -FROM ##bou_BlitzCacheProcs -WHERE 1 = 1 ' + @nl - -SELECT @sql += N' ORDER BY ' + CASE @sort_order WHEN 'cpu' THEN ' TotalCPU ' - WHEN 'reads' THEN ' TotalReads ' - WHEN 'writes' THEN ' TotalWrites ' - WHEN 'duration' THEN ' TotalDuration ' - WHEN 'executions' THEN ' ExecutionCount ' - WHEN 'avg cpu' THEN 'AverageCPU' - WHEN 'avg reads' THEN 'AverageReads' - WHEN 'avg writes' THEN 'AverageWrites' - WHEN 'avg duration' THEN 'AverageDuration' - WHEN 'avg executions' THEN 'ExecutionsPerMinute' - END + N' DESC ' -SET @sql += N' OPTION (RECOMPILE) ; ' - -EXEC sp_executesql @sql, N'@top INT', @top ; - - -GO - - - - diff --git a/QueryTemplates/Performance/sp_BlitzIndex.sql b/QueryTemplates/Performance/sp_BlitzIndex.sql deleted file mode 100644 index d31ca0a..0000000 --- a/QueryTemplates/Performance/sp_BlitzIndex.sql +++ /dev/null @@ -1,4295 +0,0 @@ -SET ANSI_NULLS ON; -SET ANSI_PADDING ON; -SET ANSI_WARNINGS ON; -SET ARITHABORT ON; -SET CONCAT_NULL_YIELDS_NULL ON; -SET QUOTED_IDENTIFIER ON; -SET STATISTICS IO OFF; -SET STATISTICS TIME OFF; -GO - -IF OBJECT_ID('dbo.sp_BlitzIndex') IS NULL - EXEC ('CREATE PROCEDURE dbo.sp_BlitzIndex AS RETURN 0;') -GO - -ALTER PROCEDURE dbo.sp_BlitzIndex - @DatabaseName NVARCHAR(128) = NULL, /*Defaults to current DB if not specified*/ - @SchemaName NVARCHAR(128) = NULL, /*Requires table_name as well.*/ - @TableName NVARCHAR(128) = NULL, /*Requires schema_name as well.*/ - @Mode TINYINT=0, /*0=Diagnose, 1=Summarize, 2=Index Usage Detail, 3=Missing Index Detail, 4=Diagnose Details*/ - /*Note:@Mode doesn't matter if you're specifying schema_name and @TableName.*/ - @Filter TINYINT = 0, /* 0=no filter (default). 1=No low-usage warnings for objects with 0 reads. 2=Only warn for objects >= 500MB */ - /*Note:@Filter doesn't do anything unless @Mode=0*/ - @SkipPartitions BIT = 0, - @SkipStatistics BIT = 1, - @GetAllDatabases BIT = 0, - @BringThePain BIT = 0, - @ThresholdMB INT = 250 /* Number of megabytes that an object must be before we include it in basic results */, - @OutputServerName NVARCHAR(256) = NULL , - @OutputDatabaseName NVARCHAR(256) = NULL , - @OutputSchemaName NVARCHAR(256) = NULL , - @OutputTableName NVARCHAR(256) = NULL , - @Help TINYINT = 0, - @VersionDate DATETIME = NULL OUTPUT -WITH RECOMPILE -AS -SET NOCOUNT ON; -SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED; -DECLARE @Version VARCHAR(30); -SET @Version = '5.6'; -SET @VersionDate = '20170801'; -IF @Help = 1 PRINT ' -/* -sp_BlitzIndex from http://FirstResponderKit.org - -This script analyzes the design and performance of your indexes. - -To learn more, visit http://FirstResponderKit.org where you can download new -versions for free, watch training videos on how it works, get more info on -the findings, contribute your own code, and more. - -Known limitations of this version: - - Only Microsoft-supported versions of SQL Server. Sorry, 2005 and 2000. - - The @OutputDatabaseName parameters are not functional yet. To check the - status of this enhancement request, visit: - https://github.com/BrentOzarULTD/SQL-Server-First-Responder-Kit/issues/221 - - Does not analyze columnstore, spatial, XML, or full text indexes. If you - would like to contribute code to analyze those, head over to Github and - check out the issues list: http://FirstResponderKit.org - - Index create statements are just to give you a rough idea of the syntax. It includes filters and fillfactor. - -- Example 1: index creates use ONLINE=? instead of ONLINE=ON / ONLINE=OFF. This is because it is important - for the user to understand if it is going to be offline and not just run a script. - -- Example 2: they do not include all the options the index may have been created with (padding, compression - filegroup/partition scheme etc.) - -- (The compression and filegroup index create syntax is not trivial because it is set at the partition - level and is not trivial to code.) - - Does not advise you about data modeling for clustered indexes and primary keys (primarily looks for signs of insanity.) - -Unknown limitations of this version: - - We knew them once, but we forgot. - -Changes - for the full list of improvements and fixes in this version, see: -https://github.com/BrentOzarULTD/SQL-Server-First-Responder-Kit/milestone/4?closed=1 - - -MIT License - -Copyright (c) 2016 Brent Ozar Unlimited - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. -' - - -DECLARE @ScriptVersionName NVARCHAR(50); -DECLARE @DaysUptime NUMERIC(23,2); -DECLARE @DatabaseID INT; -DECLARE @ObjectID INT; -DECLARE @dsql NVARCHAR(MAX); -DECLARE @params NVARCHAR(MAX); -DECLARE @msg NVARCHAR(4000); -DECLARE @ErrorSeverity INT; -DECLARE @ErrorState INT; -DECLARE @Rowcount BIGINT; -DECLARE @SQLServerProductVersion NVARCHAR(128); -DECLARE @SQLServerEdition INT; -DECLARE @FilterMB INT; -DECLARE @collation NVARCHAR(256); -DECLARE @NumDatabases INT; -DECLARE @LineFeed NVARCHAR(5); - -SET @LineFeed = CHAR(13) + CHAR(10); -SELECT @SQLServerProductVersion = CAST(SERVERPROPERTY('ProductVersion') AS NVARCHAR(128)); -SELECT @SQLServerEdition =CAST(SERVERPROPERTY('EngineEdition') AS INT); /* We default to online index creates where EngineEdition=3*/ -SET @FilterMB=250; -SELECT @ScriptVersionName = 'sp_BlitzIndex(TM) v' + @Version + ' - ' + DATENAME(MM, @VersionDate) + ' ' + RIGHT('0'+DATENAME(DD, @VersionDate),2) + ', ' + DATENAME(YY, @VersionDate) - -RAISERROR(N'Starting run. %s', 0,1, @ScriptVersionName) WITH NOWAIT; - -IF OBJECT_ID('tempdb..#IndexSanity') IS NOT NULL - DROP TABLE #IndexSanity; - -IF OBJECT_ID('tempdb..#IndexPartitionSanity') IS NOT NULL - DROP TABLE #IndexPartitionSanity; - -IF OBJECT_ID('tempdb..#IndexSanitySize') IS NOT NULL - DROP TABLE #IndexSanitySize; - -IF OBJECT_ID('tempdb..#IndexColumns') IS NOT NULL - DROP TABLE #IndexColumns; - -IF OBJECT_ID('tempdb..#MissingIndexes') IS NOT NULL - DROP TABLE #MissingIndexes; - -IF OBJECT_ID('tempdb..#ForeignKeys') IS NOT NULL - DROP TABLE #ForeignKeys; - -IF OBJECT_ID('tempdb..#BlitzIndexResults') IS NOT NULL - DROP TABLE #BlitzIndexResults; - -IF OBJECT_ID('tempdb..#IndexCreateTsql') IS NOT NULL - DROP TABLE #IndexCreateTsql; - -IF OBJECT_ID('tempdb..#DatabaseList') IS NOT NULL - DROP TABLE #DatabaseList; - -IF OBJECT_ID('tempdb..#Statistics') IS NOT NULL - DROP TABLE #Statistics; - -IF OBJECT_ID('tempdb..#PartitionCompressionInfo') IS NOT NULL - DROP TABLE #PartitionCompressionInfo; - -IF OBJECT_ID('tempdb..#ComputedColumns') IS NOT NULL - DROP TABLE #ComputedColumns; - -IF OBJECT_ID('tempdb..#TraceStatus') IS NOT NULL - DROP TABLE #TraceStatus; - -IF OBJECT_ID('tempdb..#TemporalTables') IS NOT NULL - DROP TABLE #TemporalTables; - - RAISERROR (N'Create temp tables.',0,1) WITH NOWAIT; - CREATE TABLE #BlitzIndexResults - ( - blitz_result_id INT IDENTITY PRIMARY KEY, - check_id INT NOT NULL, - index_sanity_id INT NULL, - Priority INT NULL, - findings_group VARCHAR(4000) NOT NULL, - finding VARCHAR(200) NOT NULL, - [database_name] VARCHAR(200) NULL, - URL VARCHAR(200) NOT NULL, - details NVARCHAR(4000) NOT NULL, - index_definition NVARCHAR(MAX) NOT NULL, - secret_columns NVARCHAR(MAX) NULL, - index_usage_summary NVARCHAR(MAX) NULL, - index_size_summary NVARCHAR(MAX) NULL, - create_tsql NVARCHAR(MAX) NULL, - more_info NVARCHAR(MAX)NULL - ); - - CREATE TABLE #IndexSanity - ( - [index_sanity_id] INT IDENTITY PRIMARY KEY CLUSTERED, - [database_id] SMALLINT NOT NULL , - [object_id] INT NOT NULL , - [index_id] INT NOT NULL , - [index_type] TINYINT NOT NULL, - [database_name] NVARCHAR(128) NOT NULL , - [schema_name] NVARCHAR(128) NOT NULL , - [object_name] NVARCHAR(128) NOT NULL , - index_name NVARCHAR(128) NULL , - key_column_names NVARCHAR(MAX) NULL , - key_column_names_with_sort_order NVARCHAR(MAX) NULL , - key_column_names_with_sort_order_no_types NVARCHAR(MAX) NULL , - count_key_columns INT NULL , - include_column_names NVARCHAR(MAX) NULL , - include_column_names_no_types NVARCHAR(MAX) NULL , - count_included_columns INT NULL , - partition_key_column_name NVARCHAR(MAX) NULL, - filter_definition NVARCHAR(MAX) NOT NULL , - is_indexed_view BIT NOT NULL , - is_unique BIT NOT NULL , - is_primary_key BIT NOT NULL , - is_XML BIT NOT NULL, - is_spatial BIT NOT NULL, - is_NC_columnstore BIT NOT NULL, - is_CX_columnstore BIT NOT NULL, - is_disabled BIT NOT NULL , - is_hypothetical BIT NOT NULL , - is_padded BIT NOT NULL , - fill_factor SMALLINT NOT NULL , - user_seeks BIGINT NOT NULL , - user_scans BIGINT NOT NULL , - user_lookups BIGINT NOT NULL , - user_updates BIGINT NULL , - last_user_seek DATETIME NULL , - last_user_scan DATETIME NULL , - last_user_lookup DATETIME NULL , - last_user_update DATETIME NULL , - is_referenced_by_foreign_key BIT DEFAULT(0), - secret_columns NVARCHAR(MAX) NULL, - count_secret_columns INT NULL, - create_date DATETIME NOT NULL, - modify_date DATETIME NOT NULL, - [db_schema_object_name] AS [schema_name] + '.' + [object_name] , - [db_schema_object_indexid] AS [schema_name] + '.' + [object_name] - + CASE WHEN [index_name] IS NOT NULL THEN '.' + index_name - ELSE '' - END + ' (' + CAST(index_id AS NVARCHAR(20)) + ')' , - first_key_column_name AS CASE WHEN count_key_columns > 1 - THEN LEFT(key_column_names, CHARINDEX(',', key_column_names, 0) - 1) - ELSE key_column_names - END , - index_definition AS - CASE WHEN partition_key_column_name IS NOT NULL - THEN N'[PARTITIONED BY:' + partition_key_column_name + N']' - ELSE '' - END + - CASE index_id - WHEN 0 THEN N'[HEAP] ' - WHEN 1 THEN N'[CX] ' - ELSE N'' END + CASE WHEN is_indexed_view = 1 THEN '[VIEW] ' - ELSE N'' END + CASE WHEN is_primary_key = 1 THEN N'[PK] ' - ELSE N'' END + CASE WHEN is_XML = 1 THEN N'[XML] ' - ELSE N'' END + CASE WHEN is_spatial = 1 THEN N'[SPATIAL] ' - ELSE N'' END + CASE WHEN is_NC_columnstore = 1 THEN N'[COLUMNSTORE] ' - ELSE N'' END + CASE WHEN is_disabled = 1 THEN N'[DISABLED] ' - ELSE N'' END + CASE WHEN is_hypothetical = 1 THEN N'[HYPOTHETICAL] ' - ELSE N'' END + CASE WHEN is_unique = 1 AND is_primary_key = 0 THEN N'[UNIQUE] ' - ELSE N'' END + CASE WHEN count_key_columns > 0 THEN - N'[' + CAST(count_key_columns AS VARCHAR(10)) + N' KEY' - + CASE WHEN count_key_columns > 1 THEN N'S' ELSE N'' END - + N'] ' + LTRIM(key_column_names_with_sort_order) - ELSE N'' END + CASE WHEN count_included_columns > 0 THEN - N' [' + CAST(count_included_columns AS VARCHAR(10)) + N' INCLUDE' + - + CASE WHEN count_included_columns > 1 THEN N'S' ELSE N'' END - + N'] ' + include_column_names - ELSE N'' END + CASE WHEN filter_definition <> N'' THEN N' [FILTER] ' + filter_definition - ELSE N'' END , - [total_reads] AS user_seeks + user_scans + user_lookups, - [reads_per_write] AS CAST(CASE WHEN user_updates > 0 - THEN ( user_seeks + user_scans + user_lookups ) / (1.0 * user_updates) - ELSE 0 END AS MONEY) , - [index_usage_summary] AS N'Reads: ' + - REPLACE(CONVERT(NVARCHAR(30),CAST((user_seeks + user_scans + user_lookups) AS MONEY), 1), '.00', '') - + CASE WHEN user_seeks + user_scans + user_lookups > 0 THEN - N' (' - + RTRIM( - CASE WHEN user_seeks > 0 THEN REPLACE(CONVERT(NVARCHAR(30),CAST((user_seeks) AS MONEY), 1), '.00', '') + N' seek ' ELSE N'' END - + CASE WHEN user_scans > 0 THEN REPLACE(CONVERT(NVARCHAR(30),CAST((user_scans) AS MONEY), 1), '.00', '') + N' scan ' ELSE N'' END - + CASE WHEN user_lookups > 0 THEN REPLACE(CONVERT(NVARCHAR(30),CAST((user_lookups) AS MONEY), 1), '.00', '') + N' lookup' ELSE N'' END - ) - + N') ' - ELSE N' ' END - + N'Writes:' + - REPLACE(CONVERT(NVARCHAR(30),CAST(user_updates AS MONEY), 1), '.00', ''), - [more_info] AS N'EXEC dbo.sp_BlitzIndex @DatabaseName=' + QUOTENAME([database_name],'''') + - N', @SchemaName=' + QUOTENAME([schema_name],'''') + N', @TableName=' + QUOTENAME([object_name],'''') + N';' - ); - RAISERROR (N'Adding UQ index on #IndexSanity (database_id, object_id, index_id)',0,1) WITH NOWAIT; - IF NOT EXISTS(SELECT 1 FROM tempdb.sys.indexes WHERE name='uq_database_id_object_id_index_id') - CREATE UNIQUE INDEX uq_database_id_object_id_index_id ON #IndexSanity (database_id, object_id, index_id); - - - CREATE TABLE #IndexPartitionSanity - ( - [index_partition_sanity_id] INT IDENTITY, - [index_sanity_id] INT NULL , - [database_id] INT NOT NULL , - [object_id] INT NOT NULL , - [schema_name] NVARCHAR(128) NOT NULL, - [index_id] INT NOT NULL , - [partition_number] INT NOT NULL , - row_count BIGINT NOT NULL , - reserved_MB NUMERIC(29,2) NOT NULL , - reserved_LOB_MB NUMERIC(29,2) NOT NULL , - reserved_row_overflow_MB NUMERIC(29,2) NOT NULL , - leaf_insert_count BIGINT NULL , - leaf_delete_count BIGINT NULL , - leaf_update_count BIGINT NULL , - range_scan_count BIGINT NULL , - singleton_lookup_count BIGINT NULL , - forwarded_fetch_count BIGINT NULL , - lob_fetch_in_pages BIGINT NULL , - lob_fetch_in_bytes BIGINT NULL , - row_overflow_fetch_in_pages BIGINT NULL , - row_overflow_fetch_in_bytes BIGINT NULL , - row_lock_count BIGINT NULL , - row_lock_wait_count BIGINT NULL , - row_lock_wait_in_ms BIGINT NULL , - page_lock_count BIGINT NULL , - page_lock_wait_count BIGINT NULL , - page_lock_wait_in_ms BIGINT NULL , - index_lock_promotion_attempt_count BIGINT NULL , - index_lock_promotion_count BIGINT NULL, - data_compression_desc VARCHAR(60) NULL - ); - - CREATE TABLE #IndexSanitySize - ( - [index_sanity_size_id] INT IDENTITY NOT NULL , - [index_sanity_id] INT NULL , - [database_id] INT NOT NULL, - [schema_name] NVARCHAR(128) NOT NULL, - partition_count INT NOT NULL , - total_rows BIGINT NOT NULL , - total_reserved_MB NUMERIC(29,2) NOT NULL , - total_reserved_LOB_MB NUMERIC(29,2) NOT NULL , - total_reserved_row_overflow_MB NUMERIC(29,2) NOT NULL , - total_leaf_delete_count BIGINT NULL, - total_leaf_update_count BIGINT NULL, - total_range_scan_count BIGINT NULL, - total_singleton_lookup_count BIGINT NULL, - total_forwarded_fetch_count BIGINT NULL, - total_row_lock_count BIGINT NULL , - total_row_lock_wait_count BIGINT NULL , - total_row_lock_wait_in_ms BIGINT NULL , - avg_row_lock_wait_in_ms BIGINT NULL , - total_page_lock_count BIGINT NULL , - total_page_lock_wait_count BIGINT NULL , - total_page_lock_wait_in_ms BIGINT NULL , - avg_page_lock_wait_in_ms BIGINT NULL , - total_index_lock_promotion_attempt_count BIGINT NULL , - total_index_lock_promotion_count BIGINT NULL , - data_compression_desc VARCHAR(8000) NULL, - index_size_summary AS ISNULL( - CASE WHEN partition_count > 1 - THEN N'[' + CAST(partition_count AS NVARCHAR(10)) + N' PARTITIONS] ' - ELSE N'' - END + REPLACE(CONVERT(NVARCHAR(30),CAST([total_rows] AS MONEY), 1), N'.00', N'') + N' rows; ' - + CASE WHEN total_reserved_MB > 1024 THEN - CAST(CAST(total_reserved_MB/1024. AS NUMERIC(29,1)) AS NVARCHAR(30)) + N'GB' - ELSE - CAST(CAST(total_reserved_MB AS NUMERIC(29,1)) AS NVARCHAR(30)) + N'MB' - END - + CASE WHEN total_reserved_LOB_MB > 1024 THEN - N'; ' + CAST(CAST(total_reserved_LOB_MB/1024. AS NUMERIC(29,1)) AS NVARCHAR(30)) + N'GB LOB' - WHEN total_reserved_LOB_MB > 0 THEN - N'; ' + CAST(CAST(total_reserved_LOB_MB AS NUMERIC(29,1)) AS NVARCHAR(30)) + N'MB LOB' - ELSE '' - END - + CASE WHEN total_reserved_row_overflow_MB > 1024 THEN - N'; ' + CAST(CAST(total_reserved_row_overflow_MB/1024. AS NUMERIC(29,1)) AS NVARCHAR(30)) + N'GB Row Overflow' - WHEN total_reserved_row_overflow_MB > 0 THEN - N'; ' + CAST(CAST(total_reserved_row_overflow_MB AS NUMERIC(29,1)) AS NVARCHAR(30)) + N'MB Row Overflow' - ELSE '' - END , - N'Error- NULL in computed column'), - index_op_stats AS ISNULL( - ( - REPLACE(CONVERT(NVARCHAR(30),CAST(total_singleton_lookup_count AS MONEY), 1),N'.00',N'') + N' singleton lookups; ' - + REPLACE(CONVERT(NVARCHAR(30),CAST(total_range_scan_count AS MONEY), 1),N'.00',N'') + N' scans/seeks; ' - + REPLACE(CONVERT(NVARCHAR(30),CAST(total_leaf_delete_count AS MONEY), 1),N'.00',N'') + N' deletes; ' - + REPLACE(CONVERT(NVARCHAR(30),CAST(total_leaf_update_count AS MONEY), 1),N'.00',N'') + N' updates; ' - + CASE WHEN ISNULL(total_forwarded_fetch_count,0) >0 THEN - REPLACE(CONVERT(NVARCHAR(30),CAST(total_forwarded_fetch_count AS MONEY), 1),N'.00',N'') + N' forward records fetched; ' - ELSE N'' END - - /* rows will only be in this dmv when data is in memory for the table */ - ), N'Table metadata not in memory'), - index_lock_wait_summary AS ISNULL( - CASE WHEN total_row_lock_wait_count = 0 AND total_page_lock_wait_count = 0 AND - total_index_lock_promotion_attempt_count = 0 THEN N'0 lock waits.' - ELSE - CASE WHEN total_row_lock_wait_count > 0 THEN - N'Row lock waits: ' + REPLACE(CONVERT(NVARCHAR(30),CAST(total_row_lock_wait_count AS MONEY), 1), N'.00', N'') - + N'; total duration: ' + - CASE WHEN total_row_lock_wait_in_ms >= 60000 THEN /*More than 1 min*/ - REPLACE(CONVERT(NVARCHAR(30),CAST((total_row_lock_wait_in_ms/60000) AS MONEY), 1), N'.00', N'') + N' minutes; ' - ELSE - REPLACE(CONVERT(NVARCHAR(30),CAST(ISNULL(total_row_lock_wait_in_ms/1000,0) AS MONEY), 1), N'.00', N'') + N' seconds; ' - END - + N'avg duration: ' + - CASE WHEN avg_row_lock_wait_in_ms >= 60000 THEN /*More than 1 min*/ - REPLACE(CONVERT(NVARCHAR(30),CAST((avg_row_lock_wait_in_ms/60000) AS MONEY), 1), N'.00', N'') + N' minutes; ' - ELSE - REPLACE(CONVERT(NVARCHAR(30),CAST(ISNULL(avg_row_lock_wait_in_ms/1000,0) AS MONEY), 1), N'.00', N'') + N' seconds; ' - END - ELSE N'' - END + - CASE WHEN total_page_lock_wait_count > 0 THEN - N'Page lock waits: ' + REPLACE(CONVERT(NVARCHAR(30),CAST(total_page_lock_wait_count AS MONEY), 1), N'.00', N'') - + N'; total duration: ' + - CASE WHEN total_page_lock_wait_in_ms >= 60000 THEN /*More than 1 min*/ - REPLACE(CONVERT(NVARCHAR(30),CAST((total_page_lock_wait_in_ms/60000) AS MONEY), 1), N'.00', N'') + N' minutes; ' - ELSE - REPLACE(CONVERT(NVARCHAR(30),CAST(ISNULL(total_page_lock_wait_in_ms/1000,0) AS MONEY), 1), N'.00', N'') + N' seconds; ' - END - + N'avg duration: ' + - CASE WHEN avg_page_lock_wait_in_ms >= 60000 THEN /*More than 1 min*/ - REPLACE(CONVERT(NVARCHAR(30),CAST((avg_page_lock_wait_in_ms/60000) AS MONEY), 1), N'.00', N'') + N' minutes; ' - ELSE - REPLACE(CONVERT(NVARCHAR(30),CAST(ISNULL(avg_page_lock_wait_in_ms/1000,0) AS MONEY), 1), N'.00', N'') + N' seconds; ' - END - ELSE N'' - END + - CASE WHEN total_index_lock_promotion_attempt_count > 0 THEN - N'Lock escalation attempts: ' + REPLACE(CONVERT(NVARCHAR(30),CAST(total_index_lock_promotion_attempt_count AS MONEY), 1), N'.00', N'') - + N'; Actual Escalations: ' + REPLACE(CONVERT(NVARCHAR(30),CAST(ISNULL(total_index_lock_promotion_count,0) AS MONEY), 1), N'.00', N'') + N'.' - ELSE N'' - END - END - ,'Error- NULL in computed column') - ); - - CREATE TABLE #IndexColumns - ( - [database_id] INT NOT NULL, - [schema_name] NVARCHAR(128), - [object_id] INT NOT NULL , - [index_id] INT NOT NULL , - [key_ordinal] INT NULL , - is_included_column BIT NULL , - is_descending_key BIT NULL , - [partition_ordinal] INT NULL , - column_name NVARCHAR(256) NOT NULL , - system_type_name NVARCHAR(256) NOT NULL, - max_length SMALLINT NOT NULL, - [precision] TINYINT NOT NULL, - [scale] TINYINT NOT NULL, - collation_name NVARCHAR(256) NULL, - is_nullable BIT NULL, - is_identity BIT NULL, - is_computed BIT NULL, - is_replicated BIT NULL, - is_sparse BIT NULL, - is_filestream BIT NULL, - seed_value BIGINT NULL, - increment_value INT NULL , - last_value BIGINT NULL, - is_not_for_replication BIT NULL - ); - - CREATE TABLE #MissingIndexes - ([database_id] INT NOT NULL, - [object_id] INT NOT NULL, - [database_name] NVARCHAR(128) NOT NULL , - [schema_name] NVARCHAR(128) NOT NULL , - [table_name] NVARCHAR(128), - [statement] NVARCHAR(512) NOT NULL, - magic_benefit_number AS (( user_seeks + user_scans ) * avg_total_user_cost * avg_user_impact), - avg_total_user_cost NUMERIC(29,4) NOT NULL, - avg_user_impact NUMERIC(29,1) NOT NULL, - user_seeks BIGINT NOT NULL, - user_scans BIGINT NOT NULL, - unique_compiles BIGINT NULL, - equality_columns NVARCHAR(4000), - inequality_columns NVARCHAR(4000), - included_columns NVARCHAR(4000), - is_low BIT, - [index_estimated_impact] AS - REPLACE(CONVERT(NVARCHAR(256),CAST(CAST( - (user_seeks + user_scans) - AS BIGINT) AS MONEY), 1), '.00', '') + N' use' - + CASE WHEN (user_seeks + user_scans) > 1 THEN N's' ELSE N'' END - +N'; Impact: ' + CAST(avg_user_impact AS NVARCHAR(30)) - + N'%; Avg query cost: ' - + CAST(avg_total_user_cost AS NVARCHAR(30)), - [missing_index_details] AS - CASE WHEN equality_columns IS NOT NULL THEN N'EQUALITY: ' + equality_columns + N' ' - ELSE N'' - END + CASE WHEN inequality_columns IS NOT NULL THEN N'INEQUALITY: ' + inequality_columns + N' ' - ELSE N'' - END + CASE WHEN included_columns IS NOT NULL THEN N'INCLUDES: ' + included_columns + N' ' - ELSE N'' - END, - [create_tsql] AS N'CREATE INDEX [ix_' + table_name + N'_' - + REPLACE(REPLACE(REPLACE(REPLACE( - ISNULL(equality_columns,N'')+ - CASE WHEN equality_columns IS NOT NULL AND inequality_columns IS NOT NULL THEN N'_' ELSE N'' END - + ISNULL(inequality_columns,''),',','') - ,'[',''),']',''),' ','_') - + CASE WHEN included_columns IS NOT NULL THEN N'_includes' ELSE N'' END + N'] ON ' - + [statement] + N' (' + ISNULL(equality_columns,N'') - + CASE WHEN equality_columns IS NOT NULL AND inequality_columns IS NOT NULL THEN N', ' ELSE N'' END - + CASE WHEN inequality_columns IS NOT NULL THEN inequality_columns ELSE N'' END + - ') ' + CASE WHEN included_columns IS NOT NULL THEN N' INCLUDE (' + included_columns + N')' ELSE N'' END - + N' WITH (' - + N'FILLFACTOR=100, ONLINE=?, SORT_IN_TEMPDB=?' - + N')' - + N';' - , - [more_info] AS N'EXEC dbo.sp_BlitzIndex @DatabaseName=' + QUOTENAME([database_name],'''') + - N', @SchemaName=' + QUOTENAME([schema_name],'''') + N', @TableName=' + QUOTENAME([table_name],'''') + N';' - ); - - CREATE TABLE #ForeignKeys ( - [database_id] INT NOT NULL, - [database_name] NVARCHAR(128) NOT NULL , - [schema_name] NVARCHAR(128) NOT NULL , - foreign_key_name NVARCHAR(256), - parent_object_id INT, - parent_object_name NVARCHAR(256), - referenced_object_id INT, - referenced_object_name NVARCHAR(256), - is_disabled BIT, - is_not_trusted BIT, - is_not_for_replication BIT, - parent_fk_columns NVARCHAR(MAX), - referenced_fk_columns NVARCHAR(MAX), - update_referential_action_desc NVARCHAR(16), - delete_referential_action_desc NVARCHAR(60) - ) - - CREATE TABLE #IndexCreateTsql ( - index_sanity_id INT NOT NULL, - create_tsql NVARCHAR(MAX) NOT NULL - ) - - CREATE TABLE #DatabaseList ( - DatabaseName NVARCHAR(256) - ) - - CREATE TABLE #PartitionCompressionInfo ( - [index_sanity_id] INT NULL, - [partition_compression_detail] VARCHAR(8000) NULL - ) - - CREATE TABLE #Statistics ( - database_id INT NOT NULL, - database_name NVARCHAR(256) NOT NULL, - table_name NVARCHAR(128) NULL, - schema_name NVARCHAR(128) NULL, - index_name NVARCHAR(128) NULL, - column_names NVARCHAR(4000) NULL, - statistics_name NVARCHAR(128) NULL, - last_statistics_update DATETIME NULL, - days_since_last_stats_update INT NULL, - rows BIGINT NULL, - rows_sampled BIGINT NULL, - percent_sampled DECIMAL(18, 1) NULL, - histogram_steps INT NULL, - modification_counter BIGINT NULL, - percent_modifications DECIMAL(18, 1) NULL, - modifications_before_auto_update INT NULL, - index_type_desc NVARCHAR(128) NULL, - table_create_date DATETIME NULL, - table_modify_date DATETIME NULL, - no_recompute BIT NULL, - has_filter BIT NULL, - filter_definition NVARCHAR(MAX) NULL - ); - - CREATE TABLE #ComputedColumns - ( - index_sanity_id INT IDENTITY(1, 1) NOT NULL, - database_name NVARCHAR(128) NULL, - database_id INT NOT NULL, - table_name NVARCHAR(128) NOT NULL, - schema_name NVARCHAR(128) NOT NULL, - column_name NVARCHAR(128) NULL, - is_nullable BIT NULL, - definition NVARCHAR(MAX) NULL, - uses_database_collation BIT NOT NULL, - is_persisted BIT NOT NULL, - is_computed BIT NOT NULL, - is_function INT NOT NULL, - column_definition NVARCHAR(MAX) NULL - ); - - CREATE TABLE #TraceStatus - ( - TraceFlag VARCHAR(10) , - status BIT , - Global BIT , - Session BIT - ); - - CREATE TABLE #TemporalTables - ( - index_sanity_id INT IDENTITY(1, 1) NOT NULL, - database_name NVARCHAR(128) NOT NULL, - database_id INT NOT NULL, - schema_name NVARCHAR(128) NOT NULL, - table_name NVARCHAR(128) NOT NULL, - history_table_name NVARCHAR(128) NOT NULL, - history_schema_name NVARCHAR(128) NOT NULL, - start_column_name NVARCHAR(128) NOT NULL, - end_column_name NVARCHAR(128) NOT NULL, - period_name NVARCHAR(128) NOT NULL - ); - -/* Sanitize our inputs */ -SELECT - @OutputServerName = QUOTENAME(@OutputServerName), - @OutputDatabaseName = QUOTENAME(@OutputDatabaseName), - @OutputSchemaName = QUOTENAME(@OutputSchemaName), - @OutputTableName = QUOTENAME(@OutputTableName) - - -IF @GetAllDatabases = 1 - BEGIN - INSERT INTO #DatabaseList (DatabaseName) - SELECT DB_NAME(database_id) - FROM sys.databases - WHERE user_access_desc='MULTI_USER' - AND state_desc = 'ONLINE' - AND database_id > 4 - AND DB_NAME(database_id) NOT LIKE 'ReportServer%' - AND is_distributor = 0; - END -ELSE - BEGIN - INSERT INTO #DatabaseList - ( DatabaseName ) - SELECT CASE WHEN @DatabaseName IS NULL OR @DatabaseName = N'' THEN DB_NAME() - ELSE @DatabaseName END - END - -SET @NumDatabases = @@ROWCOUNT; - -/* Running on 50+ databases can take a reaaallly long time, so we want explicit permission to do so (and only after warning about it) */ - -BEGIN TRY - IF @NumDatabases >= 50 AND @BringThePain != 1 - BEGIN - - INSERT #BlitzIndexResults ( Priority, check_id, findings_group, finding, URL, details, index_definition, - index_usage_summary, index_size_summary ) - VALUES ( -1, 0 , - @ScriptVersionName, - CASE WHEN @GetAllDatabases = 1 THEN N'All Databases' ELSE N'Database ' + QUOTENAME(@DatabaseName) + N' as of ' + CONVERT(NVARCHAR(16),GETDATE(),121) END, - N'From Your Community Volunteers' , N'http://www.BrentOzar.com/BlitzIndex' , - N'' - , N'',N'' - ); - INSERT #BlitzIndexResults ( Priority, check_id, findings_group, finding, database_name, URL, details, index_definition, - index_usage_summary, index_size_summary ) - VALUES ( 1, 0 , - N'You''re trying to run sp_BlitzIndex on a server with ' + CAST(@NumDatabases AS NVARCHAR(8)) + N' databases. ', - N'Running sp_BlitzIndex on a server with 50+ databases may cause temporary insanity for the server and/or user.', - N'If you''re sure you want to do this, run again with the parameter @BringThePain = 1.', - 'http://FirstResponderKit.org', '', '', '', '' - ); - - SELECT bir.blitz_result_id, - bir.check_id, - bir.index_sanity_id, - bir.Priority, - bir.findings_group, - bir.finding, - bir.database_name, - bir.URL, - bir.details, - bir.index_definition, - bir.secret_columns, - bir.index_usage_summary, - bir.index_size_summary, - bir.create_tsql, - bir.more_info - FROM #BlitzIndexResults AS bir - - RETURN; - - END -END TRY -BEGIN CATCH - RAISERROR (N'Failure to execute due to number of databases.', 0,1) WITH NOWAIT; - - SELECT @msg = ERROR_MESSAGE(), @ErrorSeverity = ERROR_SEVERITY(), @ErrorState = ERROR_STATE(); - - RAISERROR (@msg, - @ErrorSeverity, - @ErrorState - ); - - WHILE @@trancount > 0 - ROLLBACK; - - RETURN; - END CATCH; - -/* Permission granted or unnecessary? Ok, let's go! */ - -DECLARE c1 CURSOR -LOCAL FAST_FORWARD -FOR -SELECT DatabaseName FROM #DatabaseList ORDER BY DatabaseName - -OPEN c1 -FETCH NEXT FROM c1 INTO @DatabaseName - WHILE @@FETCH_STATUS = 0 -BEGIN - - RAISERROR (@LineFeed, 0, 1) WITH NOWAIT; - RAISERROR (@LineFeed, 0, 1) WITH NOWAIT; - RAISERROR (@DatabaseName, 0, 1) WITH NOWAIT; - -SELECT @DatabaseID = [database_id] -FROM sys.databases - WHERE [name] = @DatabaseName - AND user_access_desc='MULTI_USER' - AND state_desc = 'ONLINE'; - -/* Last startup */ -SELECT @DaysUptime = CAST(DATEDIFF(hh,create_date,GETDATE())/24. AS NUMERIC (23,2)) -FROM sys.databases -WHERE database_id = 2; - -IF @DaysUptime = 0 SET @DaysUptime = .01; - ----------------------------------------- ---STEP 1: OBSERVE THE PATIENT ---This step puts index information into temp tables. ----------------------------------------- -BEGIN TRY - BEGIN - - --Validate SQL Server Verson - - IF (SELECT LEFT(@SQLServerProductVersion, - CHARINDEX('.',@SQLServerProductVersion,0)-1 - )) <= 9 - BEGIN - SET @msg=N'sp_BlitzIndex is only supported on SQL Server 2008 and higher. The version of this instance is: ' + @SQLServerProductVersion; - RAISERROR(@msg,16,1); - END - - --Short circuit here if database name does not exist. - IF @DatabaseName IS NULL OR @DatabaseID IS NULL - BEGIN - SET @msg='Database does not exist or is not online/multi-user: cannot proceed.' - RAISERROR(@msg,16,1); - END - - --Validate parameters. - IF (@Mode NOT IN (0,1,2,3,4)) - BEGIN - SET @msg=N'Invalid @Mode parameter. 0=diagnose, 1=summarize, 2=index detail, 3=missing index detail, 4=diagnose detail'; - RAISERROR(@msg,16,1); - END - - IF (@Mode <> 0 AND @TableName IS NOT NULL) - BEGIN - SET @msg=N'Setting the @Mode doesn''t change behavior if you supply @TableName. Use default @Mode=0 to see table detail.'; - RAISERROR(@msg,16,1); - END - - IF ((@Mode <> 0 OR @TableName IS NOT NULL) AND @Filter <> 0) - BEGIN - SET @msg=N'@Filter only appies when @Mode=0 and @TableName is not specified. Please try again.'; - RAISERROR(@msg,16,1); - END - - IF (@SchemaName IS NOT NULL AND @TableName IS NULL) - BEGIN - SET @msg='We can''t run against a whole schema! Specify a @TableName, or leave both NULL for diagnosis.' - RAISERROR(@msg,16,1); - END - - - IF (@TableName IS NOT NULL AND @SchemaName IS NULL) - BEGIN - SET @SchemaName=N'dbo' - SET @msg='@SchemaName wasn''t specified-- assuming schema=dbo.' - RAISERROR(@msg,1,1) WITH NOWAIT; - END - - --If a table is specified, grab the object id. - --Short circuit if it doesn't exist. - IF @TableName IS NOT NULL - BEGIN - SET @dsql = N' - SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED; - SELECT @ObjectID= OBJECT_ID - FROM ' + QUOTENAME(@DatabaseName) + N'.sys.objects AS so - JOIN ' + QUOTENAME(@DatabaseName) + N'.sys.schemas AS sc on - so.schema_id=sc.schema_id - where so.type in (''U'', ''V'') - and so.name=' + QUOTENAME(@TableName,'''')+ N' - and sc.name=' + QUOTENAME(@SchemaName,'''')+ N' - /*Has a row in sys.indexes. This lets us get indexed views.*/ - and exists ( - SELECT si.name - FROM ' + QUOTENAME(@DatabaseName) + '.sys.indexes AS si - WHERE so.object_id=si.object_id) - OPTION (RECOMPILE);'; - - SET @params='@ObjectID INT OUTPUT' - - IF @dsql IS NULL - RAISERROR('@dsql is null',16,1); - - EXEC sp_executesql @dsql, @params, @ObjectID=@ObjectID OUTPUT; - - IF @ObjectID IS NULL - BEGIN - SET @msg=N'Oh, this is awkward. I can''t find the table or indexed view you''re looking for in that database.' + CHAR(10) + - N'Please check your parameters.' - RAISERROR(@msg,1,1); - RETURN; - END - END - - --set @collation - SELECT @collation=collation_name - FROM sys.databases - WHERE database_id=@DatabaseID; - - --insert columns for clustered indexes and heaps - --collect info on identity columns for this one - SET @dsql = N'SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED; - SELECT ' + CAST(@DatabaseID AS NVARCHAR(16)) + ', - s.name, - si.object_id, - si.index_id, - sc.key_ordinal, - sc.is_included_column, - sc.is_descending_key, - sc.partition_ordinal, - c.name as column_name, - st.name as system_type_name, - c.max_length, - c.[precision], - c.[scale], - c.collation_name, - c.is_nullable, - c.is_identity, - c.is_computed, - c.is_replicated, - ' + CASE WHEN @SQLServerProductVersion NOT LIKE '9%' THEN N'c.is_sparse' ELSE N'NULL as is_sparse' END + N', - ' + CASE WHEN @SQLServerProductVersion NOT LIKE '9%' THEN N'c.is_filestream' ELSE N'NULL as is_filestream' END + N', - CAST(ic.seed_value AS BIGINT), - CAST(ic.increment_value AS INT), - CAST(ic.last_value AS BIGINT), - ic.is_not_for_replication - FROM ' + QUOTENAME(@DatabaseName) + N'.sys.indexes si - JOIN ' + QUOTENAME(@DatabaseName) + N'.sys.columns c ON - si.object_id=c.object_id - LEFT JOIN ' + QUOTENAME(@DatabaseName) + N'.sys.index_columns sc ON - sc.object_id = si.object_id - and sc.index_id=si.index_id - AND sc.column_id=c.column_id - LEFT JOIN ' + QUOTENAME(@DatabaseName) + N'.sys.identity_columns ic ON - c.object_id=ic.object_id and - c.column_id=ic.column_id - JOIN ' + QUOTENAME(@DatabaseName) + N'.sys.types st ON - c.system_type_id=st.system_type_id - AND c.user_type_id=st.user_type_id - JOIN ' + QUOTENAME(@DatabaseName) + N'.sys.objects AS so ON si.object_id = so.object_id - AND so.is_ms_shipped = 0 - JOIN ' + QUOTENAME(@DatabaseName) + N'.sys.schemas AS s ON s.schema_id = so.schema_id - WHERE si.index_id in (0,1) ' - + CASE WHEN @ObjectID IS NOT NULL - THEN N' AND si.object_id=' + CAST(@ObjectID AS NVARCHAR(30)) - ELSE N'' END - + N'OPTION (RECOMPILE);'; - - IF @dsql IS NULL - RAISERROR('@dsql is null',16,1); - - RAISERROR (N'Inserting data into #IndexColumns for clustered indexes and heaps',0,1) WITH NOWAIT; - INSERT #IndexColumns ( database_id, [schema_name], [object_id], index_id, key_ordinal, is_included_column, is_descending_key, partition_ordinal, - column_name, system_type_name, max_length, precision, scale, collation_name, is_nullable, is_identity, is_computed, - is_replicated, is_sparse, is_filestream, seed_value, increment_value, last_value, is_not_for_replication ) - EXEC sp_executesql @dsql; - - --insert columns for nonclustered indexes - --this uses a full join to sys.index_columns - --We don't collect info on identity columns here. They may be in NC indexes, but we just analyze identities in the base table. - SET @dsql = N'SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED; - SELECT ' + CAST(@DatabaseID AS NVARCHAR(16)) + ', - s.name, - si.object_id, - si.index_id, - sc.key_ordinal, - sc.is_included_column, - sc.is_descending_key, - sc.partition_ordinal, - c.name as column_name, - st.name as system_type_name, - c.max_length, - c.[precision], - c.[scale], - c.collation_name, - c.is_nullable, - c.is_identity, - c.is_computed, - c.is_replicated, - ' + CASE WHEN @SQLServerProductVersion NOT LIKE '9%' THEN N'c.is_sparse' ELSE N'NULL AS is_sparse' END + N', - ' + CASE WHEN @SQLServerProductVersion NOT LIKE '9%' THEN N'c.is_filestream' ELSE N'NULL AS is_filestream' END + N' - FROM ' + QUOTENAME(@DatabaseName) + N'.sys.indexes AS si - JOIN ' + QUOTENAME(@DatabaseName) + N'.sys.columns AS c ON - si.object_id=c.object_id - JOIN ' + QUOTENAME(@DatabaseName) + N'.sys.index_columns AS sc ON - sc.object_id = si.object_id - and sc.index_id=si.index_id - AND sc.column_id=c.column_id - JOIN ' + QUOTENAME(@DatabaseName) + N'.sys.types AS st ON - c.system_type_id=st.system_type_id - AND c.user_type_id=st.user_type_id - JOIN ' + QUOTENAME(@DatabaseName) + N'.sys.objects AS so ON si.object_id = so.object_id - AND so.is_ms_shipped = 0 - JOIN ' + QUOTENAME(@DatabaseName) + N'.sys.schemas AS s ON s.schema_id = so.schema_id - WHERE si.index_id not in (0,1) ' - + CASE WHEN @ObjectID IS NOT NULL - THEN N' AND si.object_id=' + CAST(@ObjectID AS NVARCHAR(30)) - ELSE N'' END - + N'OPTION (RECOMPILE);'; - - IF @dsql IS NULL - RAISERROR('@dsql is null',16,1); - - RAISERROR (N'Inserting data into #IndexColumns for nonclustered indexes',0,1) WITH NOWAIT; - INSERT #IndexColumns ( database_id, [schema_name], [object_id], index_id, key_ordinal, is_included_column, is_descending_key, partition_ordinal, - column_name, system_type_name, max_length, precision, scale, collation_name, is_nullable, is_identity, is_computed, - is_replicated, is_sparse, is_filestream ) - EXEC sp_executesql @dsql; - - SET @dsql = N'SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED; - SELECT ' + CAST(@DatabaseID AS NVARCHAR(10)) + ' AS database_id, - so.object_id, - si.index_id, - si.type, - ' + QUOTENAME(@DatabaseName, '''') + ' AS database_name, - COALESCE(sc.NAME, ''Unknown'') AS [schema_name], - COALESCE(so.name, ''Unknown'') AS [object_name], - COALESCE(si.name, ''Unknown'') AS [index_name], - CASE WHEN so.[type] = CAST(''V'' AS CHAR(2)) THEN 1 ELSE 0 END, - si.is_unique, - si.is_primary_key, - CASE when si.type = 3 THEN 1 ELSE 0 END AS is_XML, - CASE when si.type = 4 THEN 1 ELSE 0 END AS is_spatial, - CASE when si.type = 6 THEN 1 ELSE 0 END AS is_NC_columnstore, - CASE when si.type = 5 then 1 else 0 end as is_CX_columnstore, - si.is_disabled, - si.is_hypothetical, - si.is_padded, - si.fill_factor,' - + CASE WHEN @SQLServerProductVersion NOT LIKE '9%' THEN ' - CASE WHEN si.filter_definition IS NOT NULL THEN si.filter_definition - ELSE '''' - END AS filter_definition' ELSE ''''' AS filter_definition' END + ' - , ISNULL(us.user_seeks, 0), ISNULL(us.user_scans, 0), - ISNULL(us.user_lookups, 0), ISNULL(us.user_updates, 0), us.last_user_seek, us.last_user_scan, - us.last_user_lookup, us.last_user_update, - so.create_date, so.modify_date - FROM ' + QUOTENAME(@DatabaseName) + '.sys.indexes AS si WITH (NOLOCK) - JOIN ' + QUOTENAME(@DatabaseName) + '.sys.objects AS so WITH (NOLOCK) ON si.object_id = so.object_id - AND so.is_ms_shipped = 0 /*Exclude objects shipped by Microsoft*/ - AND so.type <> ''TF'' /*Exclude table valued functions*/ - JOIN ' + QUOTENAME(@DatabaseName) + '.sys.schemas sc ON so.schema_id = sc.schema_id - LEFT JOIN sys.dm_db_index_usage_stats AS us WITH (NOLOCK) ON si.[object_id] = us.[object_id] - AND si.index_id = us.index_id - AND us.database_id = '+ CAST(@DatabaseID AS NVARCHAR(10)) + ' - WHERE si.[type] IN ( 0, 1, 2, 3, 4, 5, 6 ) - /* Heaps, clustered, nonclustered, XML, spatial, Cluster Columnstore, NC Columnstore */ ' + - CASE WHEN @TableName IS NOT NULL THEN ' and so.name=' + QUOTENAME(@TableName,'''') + ' ' ELSE '' END + - 'OPTION ( RECOMPILE ); - '; - IF @dsql IS NULL - RAISERROR('@dsql is null',16,1); - - RAISERROR (N'Inserting data into #IndexSanity',0,1) WITH NOWAIT; - INSERT #IndexSanity ( [database_id], [object_id], [index_id], [index_type], [database_name], [schema_name], [object_name], - index_name, is_indexed_view, is_unique, is_primary_key, is_XML, is_spatial, is_NC_columnstore, is_CX_columnstore, - is_disabled, is_hypothetical, is_padded, fill_factor, filter_definition, user_seeks, user_scans, - user_lookups, user_updates, last_user_seek, last_user_scan, last_user_lookup, last_user_update, - create_date, modify_date ) - EXEC sp_executesql @dsql; - - - IF (@SkipPartitions = 0) - BEGIN - IF (SELECT LEFT(@SQLServerProductVersion, - CHARINDEX('.',@SQLServerProductVersion,0)-1 )) <= 2147483647 --Make change here - BEGIN - - RAISERROR (N'Preferring non-2012 syntax with LEFT JOIN to sys.dm_db_index_operational_stats',0,1) WITH NOWAIT; - - --NOTE: If you want to use the newer syntax for 2012+, you'll have to change 2147483647 to 11 on line ~819 - --This change was made because on a table with lots of paritions, the OUTER APPLY was crazy slow. - SET @dsql = N'SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED; - SELECT ' + CAST(@DatabaseID AS NVARCHAR(10)) + ' AS database_id, - ps.object_id, - s.name, - ps.index_id, - ps.partition_number, - ps.row_count, - ps.reserved_page_count * 8. / 1024. AS reserved_MB, - ps.lob_reserved_page_count * 8. / 1024. AS reserved_LOB_MB, - ps.row_overflow_reserved_page_count * 8. / 1024. AS reserved_row_overflow_MB, - os.leaf_insert_count, - os.leaf_delete_count, - os.leaf_update_count, - os.range_scan_count, - os.singleton_lookup_count, - os.forwarded_fetch_count, - os.lob_fetch_in_pages, - os.lob_fetch_in_bytes, - os.row_overflow_fetch_in_pages, - os.row_overflow_fetch_in_bytes, - os.row_lock_count, - os.row_lock_wait_count, - os.row_lock_wait_in_ms, - os.page_lock_count, - os.page_lock_wait_count, - os.page_lock_wait_in_ms, - os.index_lock_promotion_attempt_count, - os.index_lock_promotion_count, - ' + CASE WHEN @SQLServerProductVersion NOT LIKE '9%' THEN 'par.data_compression_desc ' ELSE 'null as data_compression_desc' END + ' - FROM ' + QUOTENAME(@DatabaseName) + '.sys.dm_db_partition_stats AS ps - JOIN ' + QUOTENAME(@DatabaseName) + '.sys.partitions AS par on ps.partition_id=par.partition_id - JOIN ' + QUOTENAME(@DatabaseName) + '.sys.objects AS so ON ps.object_id = so.object_id - AND so.is_ms_shipped = 0 /*Exclude objects shipped by Microsoft*/ - AND so.type <> ''TF'' /*Exclude table valued functions*/ - JOIN ' + QUOTENAME(@DatabaseName) + '.sys.schemas AS s ON s.schema_id = so.schema_id - LEFT JOIN ' + QUOTENAME(@DatabaseName) + '.sys.dm_db_index_operational_stats(' - + CAST(@DatabaseID AS NVARCHAR(10)) + ', NULL, NULL,NULL) AS os ON - ps.object_id=os.object_id and ps.index_id=os.index_id and ps.partition_number=os.partition_number - WHERE 1=1 - ' + CASE WHEN @ObjectID IS NOT NULL THEN N'AND so.object_id=' + CAST(@ObjectID AS NVARCHAR(30)) + N' ' ELSE N' ' END + ' - ' + CASE WHEN @Filter = 2 THEN N'AND ps.reserved_page_count * 8./1024. > ' + CAST(@FilterMB AS NVARCHAR(5)) + N' ' ELSE N' ' END + ' - ORDER BY ps.object_id, ps.index_id, ps.partition_number - OPTION ( RECOMPILE ); - '; - END - ELSE - BEGIN - RAISERROR (N'Using 2012 syntax to query sys.dm_db_index_operational_stats',0,1) WITH NOWAIT; - --This is the syntax that will be used if you change 2147483647 to 11 on line ~819. - --If you have a lot of paritions and this suddenly starts running for a long time, change it back. - SET @dsql = N'SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED; - SELECT ' + CAST(@DatabaseID AS NVARCHAR(10)) + ' AS database_id, - ps.object_id, - s.name, - ps.index_id, - ps.partition_number, - ps.row_count, - ps.reserved_page_count * 8. / 1024. AS reserved_MB, - ps.lob_reserved_page_count * 8. / 1024. AS reserved_LOB_MB, - ps.row_overflow_reserved_page_count * 8. / 1024. AS reserved_row_overflow_MB, - os.leaf_insert_count, - os.leaf_delete_count, - os.leaf_update_count, - os.range_scan_count, - os.singleton_lookup_count, - os.forwarded_fetch_count, - os.lob_fetch_in_pages, - os.lob_fetch_in_bytes, - os.row_overflow_fetch_in_pages, - os.row_overflow_fetch_in_bytes, - os.row_lock_count, - os.row_lock_wait_count, - os.row_lock_wait_in_ms, - os.page_lock_count, - os.page_lock_wait_count, - os.page_lock_wait_in_ms, - os.index_lock_promotion_attempt_count, - os.index_lock_promotion_count, - ' + CASE WHEN @SQLServerProductVersion NOT LIKE '9%' THEN N'par.data_compression_desc ' ELSE N'null as data_compression_desc' END + N' - FROM ' + QUOTENAME(@DatabaseName) + N'.sys.dm_db_partition_stats AS ps - JOIN ' + QUOTENAME(@DatabaseName) + N'.sys.partitions AS par on ps.partition_id=par.partition_id - JOIN ' + QUOTENAME(@DatabaseName) + N'.sys.objects AS so ON ps.object_id = so.object_id - AND so.is_ms_shipped = 0 /*Exclude objects shipped by Microsoft*/ - AND so.type <> ''TF'' /*Exclude table valued functions*/ - JOIN ' + QUOTENAME(@DatabaseName) + '.sys.schemas AS s ON s.schema_id = so.schema_id - OUTER APPLY ' + QUOTENAME(@DatabaseName) + N'.sys.dm_db_index_operational_stats(' - + CAST(@DatabaseID AS NVARCHAR(10)) + N', ps.object_id, ps.index_id,ps.partition_number) AS os - WHERE 1=1 - ' + CASE WHEN @ObjectID IS NOT NULL THEN N'AND so.object_id=' + CAST(@ObjectID AS NVARCHAR(30)) + N' ' ELSE N' ' END + N' - ' + CASE WHEN @Filter = 2 THEN N'AND ps.reserved_page_count * 8./1024. > ' + CAST(@FilterMB AS NVARCHAR(5)) + N' ' ELSE N' ' END + ' - ORDER BY ps.object_id, ps.index_id, ps.partition_number - OPTION ( RECOMPILE ); - '; - END; - - IF @dsql IS NULL - RAISERROR('@dsql is null',16,1); - - RAISERROR (N'Inserting data into #IndexPartitionSanity',0,1) WITH NOWAIT; - INSERT #IndexPartitionSanity ( [database_id], - [object_id], - [schema_name], - index_id, - partition_number, - row_count, - reserved_MB, - reserved_LOB_MB, - reserved_row_overflow_MB, - leaf_insert_count, - leaf_delete_count, - leaf_update_count, - range_scan_count, - singleton_lookup_count, - forwarded_fetch_count, - lob_fetch_in_pages, - lob_fetch_in_bytes, - row_overflow_fetch_in_pages, - row_overflow_fetch_in_bytes, - row_lock_count, - row_lock_wait_count, - row_lock_wait_in_ms, - page_lock_count, - page_lock_wait_count, - page_lock_wait_in_ms, - index_lock_promotion_attempt_count, - index_lock_promotion_count, - data_compression_desc ) - EXEC sp_executesql @dsql; - - END; --End Check For @SkipPartitions = 0 - - - - RAISERROR (N'Inserting data into #MissingIndexes',0,1) WITH NOWAIT; - SET @dsql=N'SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED; - SELECT id.database_id, id.object_id, ' + QUOTENAME(@DatabaseName,'''') + N', sc.[name], so.[name], id.statement , gs.avg_total_user_cost, - gs.avg_user_impact, gs.user_seeks, gs.user_scans, gs.unique_compiles,id.equality_columns, - id.inequality_columns,id.included_columns - FROM sys.dm_db_missing_index_groups ig - JOIN sys.dm_db_missing_index_details id ON ig.index_handle = id.index_handle - JOIN sys.dm_db_missing_index_group_stats gs ON ig.index_group_handle = gs.group_handle - JOIN ' + QUOTENAME(@DatabaseName) + N'.sys.objects so on - id.object_id=so.object_id - JOIN ' + QUOTENAME(@DatabaseName) + N'.sys.schemas sc on - so.schema_id=sc.schema_id - WHERE id.database_id = ' + CAST(@DatabaseID AS NVARCHAR(30)) + ' - ' + CASE WHEN @ObjectID IS NULL THEN N'' - ELSE N'and id.object_id=' + CAST(@ObjectID AS NVARCHAR(30)) - END + - N'OPTION (RECOMPILE);' - - IF @dsql IS NULL - RAISERROR('@dsql is null',16,1); - INSERT #MissingIndexes ( [database_id], [object_id], [database_name], [schema_name], [table_name], [statement], avg_total_user_cost, - avg_user_impact, user_seeks, user_scans, unique_compiles, equality_columns, - inequality_columns, included_columns) - EXEC sp_executesql @dsql; - - SET @dsql = N' - SELECT DB_ID(' + QUOTENAME(@DatabaseName,'''') + N') AS [database_id], ' - + QUOTENAME(@DatabaseName,'''') + N' AS [database_name], - s.name, - fk_object.name AS foreign_key_name, - parent_object.[object_id] AS parent_object_id, - parent_object.name AS parent_object_name, - referenced_object.[object_id] AS referenced_object_id, - referenced_object.name AS referenced_object_name, - fk.is_disabled, - fk.is_not_trusted, - fk.is_not_for_replication, - parent.fk_columns, - referenced.fk_columns, - [update_referential_action_desc], - [delete_referential_action_desc] - FROM ' + QUOTENAME(@DatabaseName) + N'.sys.foreign_keys fk - JOIN ' + QUOTENAME(@DatabaseName) + N'.sys.objects fk_object ON fk.object_id=fk_object.object_id - JOIN ' + QUOTENAME(@DatabaseName) + N'.sys.objects parent_object ON fk.parent_object_id=parent_object.object_id - JOIN ' + QUOTENAME(@DatabaseName) + N'.sys.objects referenced_object ON fk.referenced_object_id=referenced_object.object_id - JOIN ' + QUOTENAME(@DatabaseName) + N'.sys.schemas AS s ON fk.schema_id=s.schema_id - CROSS APPLY ( SELECT STUFF( (SELECT N'', '' + c_parent.name AS fk_columns - FROM ' + QUOTENAME(@DatabaseName) + N'.sys.foreign_key_columns fkc - JOIN ' + QUOTENAME(@DatabaseName) + N'.sys.columns c_parent ON fkc.parent_object_id=c_parent.[object_id] - AND fkc.parent_column_id=c_parent.column_id - WHERE fk.parent_object_id=fkc.parent_object_id - AND fk.[object_id]=fkc.constraint_object_id - ORDER BY fkc.constraint_column_id - FOR XML PATH('''') , - TYPE).value(''.'', ''varchar(max)''), 1, 1, '''')/*This is how we remove the first comma*/ ) parent ( fk_columns ) - CROSS APPLY ( SELECT STUFF( (SELECT N'', '' + c_referenced.name AS fk_columns - FROM ' + QUOTENAME(@DatabaseName) + N'.sys. foreign_key_columns fkc - JOIN ' + QUOTENAME(@DatabaseName) + N'.sys.columns c_referenced ON fkc.referenced_object_id=c_referenced.[object_id] - AND fkc.referenced_column_id=c_referenced.column_id - WHERE fk.referenced_object_id=fkc.referenced_object_id - and fk.[object_id]=fkc.constraint_object_id - ORDER BY fkc.constraint_column_id /*order by col name, we don''t have anything better*/ - FOR XML PATH('''') , - TYPE).value(''.'', ''varchar(max)''), 1, 1, '''') ) referenced ( fk_columns ) - ' + CASE WHEN @ObjectID IS NOT NULL THEN - 'WHERE fk.parent_object_id=' + CAST(@ObjectID AS NVARCHAR(30)) + N' OR fk.referenced_object_id=' + CAST(@ObjectID AS NVARCHAR(30)) + N' ' - ELSE N' ' END + ' - ORDER BY parent_object_name, foreign_key_name - OPTION (RECOMPILE);'; - IF @dsql IS NULL - RAISERROR('@dsql is null',16,1); - - RAISERROR (N'Inserting data into #ForeignKeys',0,1) WITH NOWAIT; - INSERT #ForeignKeys ( [database_id], [database_name], [schema_name], foreign_key_name, parent_object_id,parent_object_name, referenced_object_id, referenced_object_name, - is_disabled, is_not_trusted, is_not_for_replication, parent_fk_columns, referenced_fk_columns, - [update_referential_action_desc], [delete_referential_action_desc] ) - EXEC sp_executesql @dsql; - - - IF @SkipStatistics = 0 - BEGIN - IF ((PARSENAME(@SQLServerProductVersion, 4) >= 12) - OR (PARSENAME(@SQLServerProductVersion, 4) = 11 AND PARSENAME(@SQLServerProductVersion, 2) >= 3000) - OR (PARSENAME(@SQLServerProductVersion, 4) = 10 AND PARSENAME(@SQLServerProductVersion, 3) = 50 AND PARSENAME(@SQLServerProductVersion, 2) >= 2500)) - BEGIN - RAISERROR (N'Gathering Statistics Info With Newer Syntax.',0,1) WITH NOWAIT; - SET @dsql=N'SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED; - SELECT DB_ID(' + QUOTENAME(@DatabaseName,'''') + N') AS [database_id], ' - + QUOTENAME(@DatabaseName,'''') + N' AS [database_name], - obj.name AS table_name, - sch.name AS schema_name, - ISNULL(i.name, ''System Or User Statistic'') AS index_name, - ca.column_names AS column_names, - s.name AS statistics_name, - CONVERT(DATETIME, ddsp.last_updated) AS last_statistics_update, - DATEDIFF(DAY, ddsp.last_updated, GETDATE()) AS days_since_last_stats_update, - ddsp.rows, - ddsp.rows_sampled, - CAST(ddsp.rows_sampled / ( 1. * NULLIF(ddsp.rows, 0) ) * 100 AS DECIMAL(18, 1)) AS percent_sampled, - ddsp.steps AS histogram_steps, - ddsp.modification_counter, - CASE WHEN ddsp.modification_counter > 0 - THEN CAST(ddsp.modification_counter / ( 1. * NULLIF(ddsp.rows, 0) ) * 100 AS DECIMAL(18, 1)) - ELSE ddsp.modification_counter - END AS percent_modifications, - CASE WHEN ddsp.rows < 500 THEN 500 - ELSE CAST(( ddsp.rows * .20 ) + 500 AS INT) - END AS modifications_before_auto_update, - ISNULL(i.type_desc, ''System Or User Statistic - N/A'') AS index_type_desc, - CONVERT(DATETIME, obj.create_date) AS table_create_date, - CONVERT(DATETIME, obj.modify_date) AS table_modify_date, - s.no_recompute, - s.has_filter, - s.filter_definition - FROM ' + QUOTENAME(@DatabaseName) + N'.sys.stats AS s - JOIN ' + QUOTENAME(@DatabaseName) + N'.sys.objects obj - ON s.object_id = obj.object_id - JOIN ' + QUOTENAME(@DatabaseName) + N'.sys.schemas sch - ON sch.schema_id = obj.schema_id - LEFT JOIN ' + QUOTENAME(@DatabaseName) + N'.sys.indexes AS i - ON i.object_id = s.object_id - AND i.index_id = s.stats_id - OUTER APPLY ' + QUOTENAME(@DatabaseName) + N'.sys.dm_db_stats_properties(s.object_id, s.stats_id) AS ddsp - CROSS APPLY ( SELECT STUFF((SELECT '', '' + c.name - FROM ' + QUOTENAME(@DatabaseName) + N'.sys.stats_columns AS sc - JOIN ' + QUOTENAME(@DatabaseName) + N'.sys.columns AS c - ON sc.column_id = c.column_id AND sc.object_id = c.object_id - WHERE sc.stats_id = s.stats_id AND sc.object_id = s.object_id - ORDER BY sc.stats_column_id - FOR XML PATH(''''), TYPE).value(''.'', ''varchar(max)''), 1, 2, '''') - ) ca (column_names) - WHERE obj.is_ms_shipped = 0 - OPTION (RECOMPILE);' - - IF @dsql IS NULL - RAISERROR('@dsql is null',16,1); - - RAISERROR (N'Inserting data into #Statistics',0,1) WITH NOWAIT; - INSERT #Statistics ( database_id, database_name, table_name, schema_name, index_name, column_names, statistics_name, last_statistics_update, - days_since_last_stats_update, rows, rows_sampled, percent_sampled, histogram_steps, modification_counter, - percent_modifications, modifications_before_auto_update, index_type_desc, table_create_date, table_modify_date, - no_recompute, has_filter, filter_definition) - - EXEC sp_executesql @dsql; - END - ELSE - BEGIN - RAISERROR (N'Gathering Statistics Info With Older Syntax.',0,1) WITH NOWAIT; - SET @dsql=N'SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED; - SELECT DB_ID(' + QUOTENAME(@DatabaseName,'''') + N') AS [database_id], ' - + QUOTENAME(@DatabaseName,'''') + N' AS [database_name], - obj.name AS table_name, - sch.name AS schema_name, - ISNULL(i.name, ''System Or User Statistic'') AS index_name, - ca.column_names AS column_names, - s.name AS statistics_name, - CONVERT(DATETIME, STATS_DATE(s.object_id, s.stats_id)) AS last_statistics_update, - DATEDIFF(DAY, STATS_DATE(s.object_id, s.stats_id), GETDATE()) AS days_since_last_stats_update, - si.rowcnt, - si.rowmodctr, - CASE WHEN si.rowmodctr > 0 THEN CAST(si.rowmodctr / ( 1. * NULLIF(si.rowcnt, 0) ) * 100 AS DECIMAL(18, 1)) - ELSE si.rowmodctr - END AS percent_modifications, - CASE WHEN si.rowcnt < 500 THEN 500 - ELSE CAST(( si.rowcnt * .20 ) + 500 AS INT) - END AS modifications_before_auto_update, - ISNULL(i.type_desc, ''System Or User Statistic - N/A'') AS index_type_desc, - CONVERT(DATETIME, obj.create_date) AS table_create_date, - CONVERT(DATETIME, obj.modify_date) AS table_modify_date, - s.no_recompute, - ' - + CASE WHEN @SQLServerProductVersion NOT LIKE '9%' - THEN N's.has_filter, - s.filter_definition' - ELSE N'NULL AS has_filter, - NULL AS filter_definition' END - + N' - FROM ' + QUOTENAME(@DatabaseName) + N'.sys.stats AS s - INNER HASH JOIN ' + QUOTENAME(@DatabaseName) + N'.sys.sysindexes si - ON si.name = s.name - INNER HASH JOIN ' + QUOTENAME(@DatabaseName) + N'.sys.objects obj - ON s.object_id = obj.object_id - INNER HASH JOIN ' + QUOTENAME(@DatabaseName) + N'.sys.schemas sch - ON sch.schema_id = obj.schema_id - LEFT HASH JOIN ' + QUOTENAME(@DatabaseName) + N'.sys.indexes AS i - ON i.object_id = s.object_id - AND i.index_id = s.stats_id - CROSS APPLY ( SELECT STUFF((SELECT '', '' + c.name - FROM ' + QUOTENAME(@DatabaseName) + N'.sys.stats_columns AS sc - JOIN ' + QUOTENAME(@DatabaseName) + N'.sys.columns AS c - ON sc.column_id = c.column_id AND sc.object_id = c.object_id - WHERE sc.stats_id = s.stats_id AND sc.object_id = s.object_id - ORDER BY sc.stats_column_id - FOR XML PATH(''''), TYPE).value(''.'', ''varchar(max)''), 1, 2, '''') - ) ca (column_names) - WHERE obj.is_ms_shipped = 0 - AND si.rowcnt > 0 - OPTION (RECOMPILE);' - - IF @dsql IS NULL - RAISERROR('@dsql is null',16,1); - - RAISERROR (N'Inserting data into #Statistics',0,1) WITH NOWAIT; - INSERT #Statistics(database_id, database_name, table_name, schema_name, index_name, column_names, statistics_name, - last_statistics_update, days_since_last_stats_update, rows, modification_counter, - percent_modifications, modifications_before_auto_update, index_type_desc, table_create_date, table_modify_date, - no_recompute, has_filter, filter_definition) - - EXEC sp_executesql @dsql; - END - - END - - IF (PARSENAME(@SQLServerProductVersion, 4) >= 10) - BEGIN - RAISERROR (N'Gathering Computed Column Info.',0,1) WITH NOWAIT; - SET @dsql=N'SELECT ' + QUOTENAME(@DatabaseName,'''') + N' AS [database_name], - DB_ID(' + QUOTENAME(@DatabaseName,'''') + N') AS [database_id], - t.name AS table_name, - s.name AS schema_name, - c.name AS column_name, - cc.is_nullable, - cc.definition, - cc.uses_database_collation, - cc.is_persisted, - cc.is_computed, - CASE WHEN cc.definition LIKE ''%.%'' THEN 1 ELSE 0 END AS is_function, - ''ALTER TABLE '' + QUOTENAME(s.name) + ''.'' + QUOTENAME(t.name) + - '' ADD '' + QUOTENAME(c.name) + '' AS '' + cc.definition + - CASE WHEN is_persisted = 1 THEN '' PERSISTED'' ELSE '''' END + '';'' COLLATE DATABASE_DEFAULT AS [column_definition] - FROM ' + QUOTENAME(@DatabaseName) + N'.sys.computed_columns AS cc - JOIN ' + QUOTENAME(@DatabaseName) + N'.sys.columns AS c - ON cc.object_id = c.object_id - AND cc.column_id = c.column_id - JOIN ' + QUOTENAME(@DatabaseName) + N'.sys.tables AS t - ON t.object_id = cc.object_id - JOIN ' + QUOTENAME(@DatabaseName) + N'.sys.schemas AS s - ON s.schema_id = t.schema_id - OPTION (RECOMPILE);' - - IF @dsql IS NULL - RAISERROR('@dsql is null',16,1); - - INSERT #ComputedColumns - ( [database_name], database_id, table_name, schema_name, column_name, is_nullable, definition, - uses_database_collation, is_persisted, is_computed, is_function, column_definition ) - EXEC sp_executesql @dsql; - - END - - RAISERROR (N'Gathering Trace Flag Information',0,1) WITH NOWAIT; - INSERT #TraceStatus - EXEC ('DBCC TRACESTATUS(-1) WITH NO_INFOMSGS') - - IF (PARSENAME(@SQLServerProductVersion, 4) >= 13) - BEGIN - RAISERROR (N'Gathering Temporal Table Info',0,1) WITH NOWAIT; - SET @dsql=N'SELECT ' + QUOTENAME(@DatabaseName,'''') + N' AS database_name, - DB_ID(' + QUOTENAME(@DatabaseName,'''') + N') AS [database_id], - s.name AS schema_name, - t.name AS table_name, - oa.hsn as history_schema_name, - oa.htn AS history_table_name, - c1.name AS start_column_name, - c2.name AS end_column_name, - p.name AS period_name - FROM ' + QUOTENAME(@DatabaseName) + N'.sys.periods AS p - INNER JOIN ' + QUOTENAME(@DatabaseName) + N'.sys.tables AS t - ON p.object_id = t.object_id - INNER JOIN ' + QUOTENAME(@DatabaseName) + N'.sys.columns AS c1 - ON t.object_id = c1.object_id - AND p.start_column_id = c1.column_id - INNER JOIN ' + QUOTENAME(@DatabaseName) + N'.sys.columns AS c2 - ON t.object_id = c2.object_id - AND p.end_column_id = c2.column_id - INNER JOIN ' + QUOTENAME(@DatabaseName) + N'.sys.schemas AS s - ON t.schema_id = s.schema_id - CROSS APPLY ( SELECT s2.name as hsn, t2.name htn - FROM ' + QUOTENAME(@DatabaseName) + N'.sys.tables AS t2 - INNER JOIN ' + QUOTENAME(@DatabaseName) + N'.sys.schemas AS s2 - ON t2.schema_id = s2.schema_id - WHERE t2.object_id = t.history_table_id - AND t2.temporal_type = 1 /*History table*/ ) AS oa - WHERE t.temporal_type IN ( 2, 4 ) /*BOL currently points to these types, but has no definition for 4*/ - OPTION (RECOMPILE); - ' - - IF @dsql IS NULL - RAISERROR('@dsql is null',16,1); - - INSERT #TemporalTables ( database_name, database_id, schema_name, table_name, history_table_name, - history_schema_name, start_column_name, end_column_name, period_name ) - - EXEC sp_executesql @dsql; - - END - -END -END TRY -BEGIN CATCH - RAISERROR (N'Failure populating temp tables.', 0,1) WITH NOWAIT; - - IF @dsql IS NOT NULL - BEGIN - SET @msg= 'Last @dsql: ' + @dsql; - RAISERROR(@msg, 0, 1) WITH NOWAIT; - END - - SELECT @msg = @DatabaseName + N' database failed to process. ' + ERROR_MESSAGE(), @ErrorSeverity = ERROR_SEVERITY(), @ErrorState = ERROR_STATE(); - RAISERROR (@msg,@ErrorSeverity, @ErrorState )WITH NOWAIT; - - - WHILE @@trancount > 0 - ROLLBACK; - - RETURN; -END CATCH; - FETCH NEXT FROM c1 INTO @DatabaseName -END -DEALLOCATE c1; - - - - - - ----------------------------------------- ---STEP 2: PREP THE TEMP TABLES ---EVERY QUERY AFTER THIS GOES AGAINST TEMP TABLES ONLY. ----------------------------------------- - -RAISERROR (N'Updating #IndexSanity.key_column_names',0,1) WITH NOWAIT; -UPDATE #IndexSanity -SET key_column_names = D1.key_column_names -FROM #IndexSanity si - CROSS APPLY ( SELECT RTRIM(STUFF( (SELECT N', ' + c.column_name - + N' {' + system_type_name + N' ' + CAST(max_length AS NVARCHAR(50)) + N'}' - AS col_definition - FROM #IndexColumns c - WHERE c.database_id= si.database_id - AND c.schema_name = si.schema_name - AND c.object_id = si.object_id - AND c.index_id = si.index_id - AND c.is_included_column = 0 /*Just Keys*/ - AND c.key_ordinal > 0 /*Ignore non-key columns, such as partitioning keys*/ - ORDER BY c.object_id, c.index_id, c.key_ordinal - FOR XML PATH('') ,TYPE).value('.', 'varchar(max)'), 1, 1, '')) - ) D1 ( key_column_names ) - -RAISERROR (N'Updating #IndexSanity.partition_key_column_name',0,1) WITH NOWAIT; -UPDATE #IndexSanity -SET partition_key_column_name = D1.partition_key_column_name -FROM #IndexSanity si - CROSS APPLY ( SELECT RTRIM(STUFF( (SELECT N', ' + c.column_name AS col_definition - FROM #IndexColumns c - WHERE c.database_id= si.database_id - AND c.schema_name = si.schema_name - AND c.object_id = si.object_id - AND c.index_id = si.index_id - AND c.partition_ordinal <> 0 /*Just Partitioned Keys*/ - ORDER BY c.object_id, c.index_id, c.key_ordinal - FOR XML PATH('') , TYPE).value('.', 'varchar(max)'), 1, 1,''))) D1 - ( partition_key_column_name ) - -RAISERROR (N'Updating #IndexSanity.key_column_names_with_sort_order',0,1) WITH NOWAIT; -UPDATE #IndexSanity -SET key_column_names_with_sort_order = D2.key_column_names_with_sort_order -FROM #IndexSanity si - CROSS APPLY ( SELECT RTRIM(STUFF( (SELECT N', ' + c.column_name + CASE c.is_descending_key - WHEN 1 THEN N' DESC' - ELSE N'' - + N' {' + system_type_name + N' ' + CAST(max_length AS NVARCHAR(50)) + N'}' - END AS col_definition - FROM #IndexColumns c - WHERE c.database_id= si.database_id - AND c.schema_name = si.schema_name - AND c.object_id = si.object_id - AND c.index_id = si.index_id - AND c.is_included_column = 0 /*Just Keys*/ - AND c.key_ordinal > 0 /*Ignore non-key columns, such as partitioning keys*/ - ORDER BY c.object_id, c.index_id, c.key_ordinal - FOR XML PATH('') , TYPE).value('.', 'varchar(max)'), 1, 1, '')) - ) D2 ( key_column_names_with_sort_order ) - -RAISERROR (N'Updating #IndexSanity.key_column_names_with_sort_order_no_types (for create tsql)',0,1) WITH NOWAIT; -UPDATE #IndexSanity -SET key_column_names_with_sort_order_no_types = D2.key_column_names_with_sort_order_no_types -FROM #IndexSanity si - CROSS APPLY ( SELECT RTRIM(STUFF( (SELECT N', ' + QUOTENAME(c.column_name) + CASE c.is_descending_key - WHEN 1 THEN N' DESC' - ELSE N'' - END AS col_definition - FROM #IndexColumns c - WHERE c.database_id= si.database_id - AND c.schema_name = si.schema_name - AND c.object_id = si.object_id - AND c.index_id = si.index_id - AND c.is_included_column = 0 /*Just Keys*/ - AND c.key_ordinal > 0 /*Ignore non-key columns, such as partitioning keys*/ - ORDER BY c.object_id, c.index_id, c.key_ordinal - FOR XML PATH('') , TYPE).value('.', 'varchar(max)'), 1, 1, '')) - ) D2 ( key_column_names_with_sort_order_no_types ) - -RAISERROR (N'Updating #IndexSanity.include_column_names',0,1) WITH NOWAIT; -UPDATE #IndexSanity -SET include_column_names = D3.include_column_names -FROM #IndexSanity si - CROSS APPLY ( SELECT RTRIM(STUFF( (SELECT N', ' + c.column_name - + N' {' + system_type_name + N' ' + CAST(max_length AS NVARCHAR(50)) + N'}' - FROM #IndexColumns c - WHERE c.database_id= si.database_id - AND c.schema_name = si.schema_name - AND c.object_id = si.object_id - AND c.index_id = si.index_id - AND c.is_included_column = 1 /*Just includes*/ - ORDER BY c.column_name /*Order doesn't matter in includes, - this is here to make rows easy to compare.*/ - FOR XML PATH('') , TYPE).value('.', 'varchar(max)'), 1, 1, '')) - ) D3 ( include_column_names ); - -RAISERROR (N'Updating #IndexSanity.include_column_names_no_types (for create tsql)',0,1) WITH NOWAIT; -UPDATE #IndexSanity -SET include_column_names_no_types = D3.include_column_names_no_types -FROM #IndexSanity si - CROSS APPLY ( SELECT RTRIM(STUFF( (SELECT N', ' + QUOTENAME(c.column_name) - FROM #IndexColumns c - WHERE c.database_id= si.database_id - AND c.schema_name = si.schema_name - AND c.object_id = si.object_id - AND c.index_id = si.index_id - AND c.is_included_column = 1 /*Just includes*/ - ORDER BY c.column_name /*Order doesn't matter in includes, - this is here to make rows easy to compare.*/ - FOR XML PATH('') , TYPE).value('.', 'varchar(max)'), 1, 1, '')) - ) D3 ( include_column_names_no_types ); - -RAISERROR (N'Updating #IndexSanity.count_key_columns and count_include_columns',0,1) WITH NOWAIT; -UPDATE #IndexSanity -SET count_included_columns = D4.count_included_columns, - count_key_columns = D4.count_key_columns -FROM #IndexSanity si - CROSS APPLY ( SELECT SUM(CASE WHEN is_included_column = 'true' THEN 1 - ELSE 0 - END) AS count_included_columns, - SUM(CASE WHEN is_included_column = 'false' AND c.key_ordinal > 0 THEN 1 - ELSE 0 - END) AS count_key_columns - FROM #IndexColumns c - WHERE c.database_id= si.database_id - AND c.schema_name = si.schema_name - AND c.object_id = si.object_id - AND c.index_id = si.index_id - ) AS D4 ( count_included_columns, count_key_columns ); - -RAISERROR (N'Updating index_sanity_id on #IndexPartitionSanity',0,1) WITH NOWAIT; -UPDATE #IndexPartitionSanity -SET index_sanity_id = i.index_sanity_id -FROM #IndexPartitionSanity ps - JOIN #IndexSanity i ON ps.[object_id] = i.[object_id] - AND ps.index_id = i.index_id - AND i.database_id = ps.database_id - AND i.schema_name = ps.schema_name - - -RAISERROR (N'Inserting data into #IndexSanitySize',0,1) WITH NOWAIT; -INSERT #IndexSanitySize ( [index_sanity_id], [database_id], [schema_name], partition_count, total_rows, total_reserved_MB, - total_reserved_LOB_MB, total_reserved_row_overflow_MB, total_range_scan_count, - total_singleton_lookup_count, total_leaf_delete_count, total_leaf_update_count, - total_forwarded_fetch_count,total_row_lock_count, - total_row_lock_wait_count, total_row_lock_wait_in_ms, avg_row_lock_wait_in_ms, - total_page_lock_count, total_page_lock_wait_count, total_page_lock_wait_in_ms, - avg_page_lock_wait_in_ms, total_index_lock_promotion_attempt_count, - total_index_lock_promotion_count, data_compression_desc ) - SELECT index_sanity_id, ipp.database_id, ipp.schema_name, - COUNT(*), SUM(row_count), SUM(reserved_MB), SUM(reserved_LOB_MB), - SUM(reserved_row_overflow_MB), - SUM(range_scan_count), - SUM(singleton_lookup_count), - SUM(leaf_delete_count), - SUM(leaf_update_count), - SUM(forwarded_fetch_count), - SUM(row_lock_count), - SUM(row_lock_wait_count), - SUM(row_lock_wait_in_ms), - CASE WHEN SUM(row_lock_wait_in_ms) > 0 THEN - SUM(row_lock_wait_in_ms)/(1.*SUM(row_lock_wait_count)) - ELSE 0 END AS avg_row_lock_wait_in_ms, - SUM(page_lock_count), - SUM(page_lock_wait_count), - SUM(page_lock_wait_in_ms), - CASE WHEN SUM(page_lock_wait_in_ms) > 0 THEN - SUM(page_lock_wait_in_ms)/(1.*SUM(page_lock_wait_count)) - ELSE 0 END AS avg_page_lock_wait_in_ms, - SUM(index_lock_promotion_attempt_count), - SUM(index_lock_promotion_count), - LEFT(MAX(data_compression_info.data_compression_rollup),8000) - FROM #IndexPartitionSanity ipp - /* individual partitions can have distinct compression settings, just roll them into a list here*/ - OUTER APPLY (SELECT STUFF(( - SELECT N', ' + data_compression_desc - FROM #IndexPartitionSanity ipp2 - WHERE ipp.[object_id]=ipp2.[object_id] - AND ipp.[index_id]=ipp2.[index_id] - AND ipp.database_id = ipp2.database_id - AND ipp.schema_name = ipp2.schema_name - ORDER BY ipp2.partition_number - FOR XML PATH(''),TYPE).value('.', 'varchar(max)'), 1, 1, '')) - data_compression_info(data_compression_rollup) - GROUP BY index_sanity_id, ipp.database_id, ipp.schema_name - ORDER BY index_sanity_id -OPTION ( RECOMPILE ); - -RAISERROR (N'Determining index usefulness',0,1) WITH NOWAIT; -UPDATE #MissingIndexes -SET is_low = CASE WHEN (user_seeks + user_scans) < 10000 - OR avg_user_impact < 70. THEN 1 - ELSE 0 - END; - -RAISERROR (N'Updating #IndexSanity.referenced_by_foreign_key',0,1) WITH NOWAIT; -UPDATE #IndexSanity - SET is_referenced_by_foreign_key=1 -FROM #IndexSanity s -JOIN #ForeignKeys fk ON - s.object_id=fk.referenced_object_id - AND s.database_id=fk.database_id - AND LEFT(s.key_column_names,LEN(fk.referenced_fk_columns)) = fk.referenced_fk_columns - -RAISERROR (N'Update index_secret on #IndexSanity for NC indexes.',0,1) WITH NOWAIT; -UPDATE nc -SET secret_columns= - N'[' + - CASE tb.count_key_columns WHEN 0 THEN '1' ELSE CAST(tb.count_key_columns AS VARCHAR(10)) END + - CASE nc.is_unique WHEN 1 THEN N' INCLUDE' ELSE N' KEY' END + - CASE WHEN tb.count_key_columns > 1 THEN N'S] ' ELSE N'] ' END + - CASE tb.index_id WHEN 0 THEN '[RID]' ELSE LTRIM(tb.key_column_names) + - /* Uniquifiers only needed on non-unique clustereds-- not heaps */ - CASE tb.is_unique WHEN 0 THEN ' [UNIQUIFIER]' ELSE N'' END - END - , count_secret_columns= - CASE tb.index_id WHEN 0 THEN 1 ELSE - tb.count_key_columns + - CASE tb.is_unique WHEN 0 THEN 1 ELSE 0 END - END -FROM #IndexSanity AS nc -JOIN #IndexSanity AS tb ON nc.object_id=tb.object_id - AND nc.database_id = tb.database_id - AND nc.schema_name = tb.schema_name - AND tb.index_id IN (0,1) -WHERE nc.index_id > 1; - -RAISERROR (N'Update index_secret on #IndexSanity for heaps and non-unique clustered.',0,1) WITH NOWAIT; -UPDATE tb -SET secret_columns= CASE tb.index_id WHEN 0 THEN '[RID]' ELSE '[UNIQUIFIER]' END - , count_secret_columns = 1 -FROM #IndexSanity AS tb -WHERE tb.index_id = 0 /*Heaps-- these have the RID */ - OR (tb.index_id=1 AND tb.is_unique=0); /* Non-unique CX: has uniquifer (when needed) */ - - -RAISERROR (N'Populate #IndexCreateTsql.',0,1) WITH NOWAIT; -INSERT #IndexCreateTsql (index_sanity_id, create_tsql) -SELECT - index_sanity_id, - ISNULL ( - /* Script drops for disabled non-clustered indexes*/ - CASE WHEN is_disabled = 1 AND index_id <> 1 - THEN N'--DROP INDEX ' + QUOTENAME([index_name]) + N' ON ' - + QUOTENAME([schema_name]) + N'.' + QUOTENAME([object_name]) - ELSE - CASE index_id WHEN 0 THEN N'--I''m a Heap!' - ELSE - CASE WHEN is_XML = 1 OR is_spatial=1 THEN N'' /* Not even trying for these just yet...*/ - ELSE - CASE WHEN is_primary_key=1 THEN - N'ALTER TABLE ' + QUOTENAME([schema_name]) + - N'.' + QUOTENAME([object_name]) + - N' ADD CONSTRAINT [' + - index_name + - N'] PRIMARY KEY ' + - CASE WHEN index_id=1 THEN N'CLUSTERED (' ELSE N'(' END + - key_column_names_with_sort_order_no_types + N' )' - WHEN is_CX_columnstore= 1 THEN - N'CREATE CLUSTERED COLUMNSTORE INDEX ' + QUOTENAME(index_name) + N' on ' + QUOTENAME([schema_name]) + '.' + QUOTENAME([object_name]) - ELSE /*Else not a PK or cx columnstore */ - N'CREATE ' + - CASE WHEN is_unique=1 THEN N'UNIQUE ' ELSE N'' END + - CASE WHEN index_id=1 THEN N'CLUSTERED ' ELSE N'' END + - CASE WHEN is_NC_columnstore=1 THEN N'NONCLUSTERED COLUMNSTORE ' - ELSE N'' END + - N'INDEX [' - + index_name + N'] ON ' + - QUOTENAME([schema_name]) + '.' + QUOTENAME([object_name]) + - CASE WHEN is_NC_columnstore=1 THEN - N' (' + ISNULL(include_column_names_no_types,'') + N' )' - ELSE /*Else not colunnstore */ - N' (' + ISNULL(key_column_names_with_sort_order_no_types,'') + N' )' - + CASE WHEN include_column_names_no_types IS NOT NULL THEN - N' INCLUDE (' + include_column_names_no_types + N')' - ELSE N'' - END - END /*End non-colunnstore case */ - + CASE WHEN filter_definition <> N'' THEN N' WHERE ' + filter_definition ELSE N'' END - END /*End Non-PK index CASE */ - + CASE WHEN is_NC_columnstore=0 AND is_CX_columnstore=0 THEN - N' WITH (' - + N'FILLFACTOR=' + CASE fill_factor WHEN 0 THEN N'100' ELSE CAST(fill_factor AS NVARCHAR(5)) END + ', ' - + N'ONLINE=?, SORT_IN_TEMPDB=?' - + N')' - ELSE N'' END - + N';' - END /*End non-spatial and non-xml CASE */ - END - END, '[Unknown Error]') - AS create_tsql -FROM #IndexSanity; - -RAISERROR (N'Populate #PartitionCompressionInfo.',0,1) WITH NOWAIT; -;WITH [maps] - AS ( SELECT - index_sanity_id, - partition_number, - data_compression_desc, - partition_number - ROW_NUMBER() OVER (PARTITION BY ips.index_sanity_id, data_compression_desc ORDER BY partition_number ) AS [rN] - FROM #IndexPartitionSanity ips - ), - [grps] - AS ( SELECT MIN([maps].[partition_number]) AS [MinKey] , - MAX([maps].[partition_number]) AS [MaxKey] , - index_sanity_id, - maps.data_compression_desc - FROM [maps] - GROUP BY [maps].[rN], index_sanity_id, maps.data_compression_desc) -INSERT #PartitionCompressionInfo - (index_sanity_id, partition_compression_detail) -SELECT DISTINCT grps.index_sanity_id , SUBSTRING(( STUFF((SELECT ', ' + ' Partition' - + CASE WHEN [grps2].[MinKey] < [grps2].[MaxKey] - THEN +'s ' - + CAST([grps2].[MinKey] AS VARCHAR) - + ' - ' - + CAST([grps2].[MaxKey] AS VARCHAR) - + ' use ' + grps2.data_compression_desc - ELSE ' ' - + CAST([grps2].[MinKey] AS VARCHAR) - + ' uses ' + grps2.data_compression_desc - END AS [Partitions] - FROM [grps] AS grps2 - WHERE grps2.index_sanity_id = grps.index_sanity_id - ORDER BY grps2.MinKey, grps2.MaxKey - FOR XML PATH('') , - TYPE - ).[value]('.', 'VARCHAR(MAX)'), 1, 1, '') ), 0, 8000) AS [partition_compression_detail] -FROM grps; - -RAISERROR (N'Update #PartitionCompressionInfo.',0,1) WITH NOWAIT; -UPDATE sz -SET sz.data_compression_desc = pci.partition_compression_detail -FROM #IndexSanitySize sz -JOIN #PartitionCompressionInfo AS pci -ON pci.index_sanity_id = sz.index_sanity_id; - - - -/*This is for debugging*/ ---SELECT '#IndexSanity' AS table_name, * FROM #IndexSanity; ---SELECT '#IndexPartitionSanity' AS table_name, * FROM #IndexPartitionSanity; ---SELECT '#IndexSanitySize' AS table_name, * FROM #IndexSanitySize; ---SELECT '#IndexColumns' AS table_name, * FROM #IndexColumns; ---SELECT '#MissingIndexes' AS table_name, * FROM #MissingIndexes; ---SELECT '#ForeignKeys' AS table_name, * FROM #ForeignKeys; ---SELECT '#BlitzIndexResults' AS table_name, * FROM #BlitzIndexResults; ---SELECT '#IndexCreateTsql' AS table_name, * FROM #IndexCreateTsql; ---SELECT '#DatabaseList' AS table_name, * FROM #DatabaseList; ---SELECT '#Statistics' AS table_name, * FROM #Statistics; ---SELECT '#PartitionCompressionInfo' AS table_name, * FROM #PartitionCompressionInfo; ---SELECT '#ComputedColumns' AS table_name, * FROM #ComputedColumns; ---SELECT '#TraceStatus' AS table_name, * FROM #TraceStatus; -/*End debug*/ - - ----------------------------------------- ---STEP 3: DIAGNOSE THE PATIENT ----------------------------------------- - - -BEGIN TRY ----------------------------------------- ---If @TableName is specified, just return information for that table. ---The @Mode parameter doesn't matter if you're looking at a specific table. ----------------------------------------- -IF @TableName IS NOT NULL -BEGIN - RAISERROR(N'@TableName specified, giving detail only on that table.', 0,1) WITH NOWAIT; - - --We do a left join here in case this is a disabled NC. - --In that case, it won't have any size info/pages allocated. - - - WITH table_mode_cte AS ( - SELECT - s.db_schema_object_indexid, - s.key_column_names, - s.index_definition, - ISNULL(s.secret_columns,N'') AS secret_columns, - s.fill_factor, - s.index_usage_summary, - sz.index_op_stats, - ISNULL(sz.index_size_summary,'') /*disabled NCs will be null*/ AS index_size_summary, - partition_compression_detail , - ISNULL(sz.index_lock_wait_summary,'') AS index_lock_wait_summary, - s.is_referenced_by_foreign_key, - (SELECT COUNT(*) - FROM #ForeignKeys fk WHERE fk.parent_object_id=s.object_id - AND PATINDEX (fk.parent_fk_columns, s.key_column_names)=1) AS FKs_covered_by_index, - s.last_user_seek, - s.last_user_scan, - s.last_user_lookup, - s.last_user_update, - s.create_date, - s.modify_date, - ct.create_tsql, - 1 AS display_order - FROM #IndexSanity s - LEFT JOIN #IndexSanitySize sz ON - s.index_sanity_id=sz.index_sanity_id - LEFT JOIN #IndexCreateTsql ct ON - s.index_sanity_id=ct.index_sanity_id - LEFT JOIN #PartitionCompressionInfo pci ON - pci.index_sanity_id = s.index_sanity_id - WHERE s.[object_id]=@ObjectID - UNION ALL - SELECT N'Database ' + QUOTENAME(@DatabaseName) + N' as of ' + CONVERT(NVARCHAR(16),GETDATE(),121) + - N' (' + @ScriptVersionName + ')' , - N'SQL Server First Responder Kit' , - N'http://FirstResponderKit.org' , - N'From Your Community Volunteers', - NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL, - 0 AS display_order - ) - SELECT - db_schema_object_indexid AS [Details: db_schema.table.index(indexid)], - index_definition AS [Definition: [Property]] ColumnName {datatype maxbytes}], - secret_columns AS [Secret Columns], - fill_factor AS [Fillfactor], - index_usage_summary AS [Usage Stats], - index_op_stats AS [Op Stats], - index_size_summary AS [Size], - partition_compression_detail AS [Compression Type], - index_lock_wait_summary AS [Lock Waits], - is_referenced_by_foreign_key AS [Referenced by FK?], - FKs_covered_by_index AS [FK Covered by Index?], - last_user_seek AS [Last User Seek], - last_user_scan AS [Last User Scan], - last_user_lookup AS [Last User Lookup], - last_user_update AS [Last User Write], - create_date AS [Created], - modify_date AS [Last Modified], - create_tsql AS [Create TSQL] - FROM table_mode_cte - ORDER BY display_order ASC, key_column_names ASC - OPTION ( RECOMPILE ); - - IF (SELECT TOP 1 [object_id] FROM #MissingIndexes mi) IS NOT NULL - BEGIN - - WITH create_date AS ( - SELECT i.database_id, - i.schema_name, - i.[object_id], - ISNULL(NULLIF(MAX(DATEDIFF(DAY, i.create_date, SYSDATETIME())), 0), 1) AS create_days - FROM #IndexSanity AS i - GROUP BY i.database_id, i.schema_name, i.object_id - ) - SELECT N'Missing index.' AS Finding , - N'http://BrentOzar.com/go/Indexaphobia' AS URL , - mi.[statement] + - ' Est. Benefit: ' - + CASE WHEN magic_benefit_number >= 922337203685477 THEN '>= 922,337,203,685,477' - ELSE REPLACE(CONVERT(NVARCHAR(256),CAST(CAST( - (magic_benefit_number / CASE WHEN cd.create_days < @DaysUptime THEN cd.create_days ELSE @DaysUptime END) - AS BIGINT) AS MONEY), 1), '.00', '') - END AS [Estimated Benefit], - missing_index_details AS [Missing Index Request] , - index_estimated_impact AS [Estimated Impact], - create_tsql AS [Create TSQL] - FROM #MissingIndexes mi - LEFT JOIN create_date AS cd - ON mi.[object_id] = cd.object_id - AND mi.database_id = cd.database_id - AND mi.schema_name = cd.schema_name - WHERE mi.[object_id] = @ObjectID - /* Minimum benefit threshold = 100k/day of uptime OR since table creation date, whichever is lower*/ - AND (magic_benefit_number / CASE WHEN cd.create_days < @DaysUptime THEN cd.create_days ELSE @DaysUptime END) >= 100000 - ORDER BY is_low, magic_benefit_number DESC - OPTION ( RECOMPILE ); - END - ELSE - SELECT 'No missing indexes.' AS finding; - - SELECT - column_name AS [Column Name], - (SELECT COUNT(*) - FROM #IndexColumns c2 - WHERE c2.column_name=c.column_name - AND c2.key_ordinal IS NOT NULL) - + CASE WHEN c.index_id = 1 AND c.key_ordinal IS NOT NULL THEN - -1+ (SELECT COUNT(DISTINCT index_id) - FROM #IndexColumns c3 - WHERE c3.index_id NOT IN (0,1)) - ELSE 0 END - AS [Found In], - system_type_name + - CASE max_length WHEN -1 THEN N' (max)' ELSE - CASE - WHEN system_type_name IN (N'char',N'nchar',N'binary',N'varbinary') THEN N' (' + CAST(max_length AS NVARCHAR(20)) + N')' - WHEN system_type_name IN (N'varchar',N'nvarchar') THEN N' (' + CAST(max_length/2 AS NVARCHAR(20)) + N')' - ELSE '' - END - END - AS [Type], - CASE is_computed WHEN 1 THEN 'yes' ELSE '' END AS [Computed?], - max_length AS [Length (max bytes)], - [precision] AS [Prec], - [scale] AS [Scale], - CASE is_nullable WHEN 1 THEN 'yes' ELSE '' END AS [Nullable?], - CASE is_identity WHEN 1 THEN 'yes' ELSE '' END AS [Identity?], - CASE is_replicated WHEN 1 THEN 'yes' ELSE '' END AS [Replicated?], - CASE is_sparse WHEN 1 THEN 'yes' ELSE '' END AS [Sparse?], - CASE is_filestream WHEN 1 THEN 'yes' ELSE '' END AS [Filestream?], - collation_name AS [Collation] - FROM #IndexColumns AS c - WHERE index_id IN (0,1); - - IF (SELECT TOP 1 parent_object_id FROM #ForeignKeys) IS NOT NULL - BEGIN - SELECT [database_name] + N':' + parent_object_name + N': ' + foreign_key_name AS [Foreign Key], - parent_fk_columns AS [Foreign Key Columns], - referenced_object_name AS [Referenced Table], - referenced_fk_columns AS [Referenced Table Columns], - is_disabled AS [Is Disabled?], - is_not_trusted AS [Not Trusted?], - is_not_for_replication [Not for Replication?], - [update_referential_action_desc] AS [Cascading Updates?], - [delete_referential_action_desc] AS [Cascading Deletes?] - FROM #ForeignKeys - ORDER BY [Foreign Key] - OPTION ( RECOMPILE ); - END - ELSE - SELECT 'No foreign keys.' AS finding; -END - ---If @TableName is NOT specified... ---Act based on the @Mode and @Filter. (@Filter applies only when @Mode=0 "diagnose") -ELSE -BEGIN; - IF @Mode IN (0, 4) /* DIAGNOSE*/ - BEGIN; - RAISERROR(N'@Mode=0 or 4, we are diagnosing.', 0,1) WITH NOWAIT; - - ---------------------------------------- - --Multiple Index Personalities: Check_id 0-10 - ---------------------------------------- - BEGIN; - - --SELECT [object_id], key_column_names, database_id - -- FROM #IndexSanity - -- WHERE index_type IN (1,2) /* Clustered, NC only*/ - -- AND is_hypothetical = 0 - -- AND is_disabled = 0 - -- GROUP BY [object_id], key_column_names, database_id - -- HAVING COUNT(*) > 1 - - - RAISERROR('check_id 1: Duplicate keys', 0,1) WITH NOWAIT; - WITH duplicate_indexes - AS ( SELECT [object_id], key_column_names, database_id, [schema_name] - FROM #IndexSanity - WHERE index_type IN (1,2) /* Clustered, NC only*/ - AND is_hypothetical = 0 - AND is_disabled = 0 - AND is_primary_key = 0 - GROUP BY [object_id], key_column_names, database_id, [schema_name] - HAVING COUNT(*) > 1) - INSERT #BlitzIndexResults ( check_id, index_sanity_id, Priority, findings_group, finding, [database_name], URL, details, index_definition, - secret_columns, index_usage_summary, index_size_summary ) - SELECT 1 AS check_id, - ip.index_sanity_id, - 50 AS Priority, - 'Multiple Index Personalities' AS findings_group, - 'Duplicate keys' AS finding, - [database_name] AS [Database Name], - N'http://BrentOzar.com/go/duplicateindex' AS URL, - N'Index Name: ' + ip.index_name + N' Table Name: ' + ip.db_schema_object_name AS details, - ip.index_definition, - ip.secret_columns, - ip.index_usage_summary, - ips.index_size_summary - FROM duplicate_indexes di - JOIN #IndexSanity ip ON di.[object_id] = ip.[object_id] - AND ip.database_id = di.database_id - AND ip.[schema_name] = di.[schema_name] - AND di.key_column_names = ip.key_column_names - JOIN #IndexSanitySize ips ON ip.index_sanity_id = ips.index_sanity_id AND ip.database_id = ips.database_id - /* WHERE clause limits to only @ThresholdMB or larger duplicate indexes when getting all databases or using PainRelief mode */ - WHERE ips.total_reserved_MB >= CASE WHEN (@GetAllDatabases = 1 OR @Mode = 0) THEN @ThresholdMB ELSE ips.total_reserved_MB END - AND ip.is_primary_key = 0 - ORDER BY ip.object_id, ip.key_column_names_with_sort_order - OPTION ( RECOMPILE ); - - RAISERROR('check_id 2: Keys w/ identical leading columns.', 0,1) WITH NOWAIT; - WITH borderline_duplicate_indexes - AS ( SELECT DISTINCT database_id, [object_id], first_key_column_name, key_column_names, - COUNT([object_id]) OVER ( PARTITION BY database_id, [object_id], first_key_column_name ) AS number_dupes - FROM #IndexSanity - WHERE index_type IN (1,2) /* Clustered, NC only*/ - AND is_hypothetical=0 - AND is_disabled=0 - AND is_primary_key = 0) - INSERT #BlitzIndexResults ( check_id, index_sanity_id, Priority, findings_group, finding, [database_name], URL, details, index_definition, - secret_columns, index_usage_summary, index_size_summary ) - SELECT 2 AS check_id, - ip.index_sanity_id, - 60 AS Priority, - 'Multiple Index Personalities' AS findings_group, - 'Borderline duplicate keys' AS finding, - [database_name] AS [Database Name], - N'http://BrentOzar.com/go/duplicateindex' AS URL, - ip.db_schema_object_indexid AS details, - ip.index_definition, - ip.secret_columns, - ip.index_usage_summary, - ips.index_size_summary - FROM #IndexSanity AS ip - JOIN #IndexSanitySize ips ON ip.index_sanity_id = ips.index_sanity_id - WHERE EXISTS ( - SELECT di.[object_id] - FROM borderline_duplicate_indexes AS di - WHERE di.[object_id] = ip.[object_id] AND - di.database_id = ip.database_id AND - di.first_key_column_name = ip.first_key_column_name AND - di.key_column_names <> ip.key_column_names AND - di.number_dupes > 1 - ) - AND ip.is_primary_key = 0 - /* WHERE clause skips near-duplicate indexes when getting all databases or using PainRelief mode */ - AND NOT (@GetAllDatabases = 1 OR @Mode = 0) - - ORDER BY ip.[schema_name], ip.[object_name], ip.key_column_names, ip.include_column_names - OPTION ( RECOMPILE ); - - END - ---------------------------------------- - --Aggressive Indexes: Check_id 10-19 - ---------------------------------------- - BEGIN; - - RAISERROR(N'check_id 11: Total lock wait time > 5 minutes (row + page) with long average waits', 0,1) WITH NOWAIT; - INSERT #BlitzIndexResults ( check_id, index_sanity_id, Priority, findings_group, finding, [database_name], URL, details, index_definition, - secret_columns, index_usage_summary, index_size_summary ) - SELECT 11 AS check_id, - i.index_sanity_id, - 10 AS Priority, - N'Aggressive Indexes' AS findings_group, - N'Total lock wait time > 5 minutes (row + page) with long average waits' AS finding, - [database_name] AS [Database Name], - N'http://BrentOzar.com/go/AggressiveIndexes' AS URL, - i.db_schema_object_indexid + N': ' + - sz.index_lock_wait_summary + N' NC indexes on table: ' + - CAST(SUM(CASE WHEN index_id NOT IN (0,1) THEN 1 ELSE 0 END) - AS NVARCHAR(30)) AS details, - i.index_definition, - i.secret_columns, - i.index_usage_summary, - sz.index_size_summary - FROM #IndexSanity AS i - JOIN #IndexSanitySize AS sz ON i.index_sanity_id = sz.index_sanity_id - WHERE (total_row_lock_wait_in_ms + total_page_lock_wait_in_ms) > 300000 - AND (sz.avg_page_lock_wait_in_ms + sz.avg_row_lock_wait_in_ms) > 5000 - GROUP BY i.index_sanity_id, [database_name], i.db_schema_object_indexid, sz.index_lock_wait_summary, i.index_definition, i.secret_columns, i.index_usage_summary, sz.index_size_summary, sz.index_sanity_id - OPTION ( RECOMPILE ); - - RAISERROR(N'check_id 12: Total lock wait time > 5 minutes (row + page) with short average waits', 0,1) WITH NOWAIT; - INSERT #BlitzIndexResults ( check_id, index_sanity_id, Priority, findings_group, finding, [database_name], URL, details, index_definition, - secret_columns, index_usage_summary, index_size_summary ) - SELECT 12 AS check_id, - i.index_sanity_id, - 10 AS Priority, - N'Aggressive Indexes' AS findings_group, - N'Total lock wait time > 5 minutes (row + page) with short average waits' AS finding, - [database_name] AS [Database Name], - N'http://BrentOzar.com/go/AggressiveIndexes' AS URL, - i.db_schema_object_indexid + N': ' + - sz.index_lock_wait_summary + N' NC indexes on table: ' + - CAST(SUM(CASE WHEN index_id NOT IN (0,1) THEN 1 ELSE 0 END) - AS NVARCHAR(30)) AS details, - i.index_definition, - i.secret_columns, - i.index_usage_summary, - sz.index_size_summary - FROM #IndexSanity AS i - JOIN #IndexSanitySize AS sz ON i.index_sanity_id = sz.index_sanity_id - WHERE (total_row_lock_wait_in_ms + total_page_lock_wait_in_ms) > 300000 - AND (sz.avg_page_lock_wait_in_ms + sz.avg_row_lock_wait_in_ms) < 5000 - GROUP BY i.index_sanity_id, [database_name], i.db_schema_object_indexid, sz.index_lock_wait_summary, i.index_definition, i.secret_columns, i.index_usage_summary, sz.index_size_summary, sz.index_sanity_id - OPTION ( RECOMPILE ); - - END - - ---------------------------------------- - --Index Hoarder: Check_id 20-29 - ---------------------------------------- - BEGIN - RAISERROR(N'check_id 20: >=7 NC indexes on any given table. Yes, 7 is an arbitrary number.', 0,1) WITH NOWAIT; - INSERT #BlitzIndexResults ( check_id, index_sanity_id, Priority, findings_group, finding, [database_name], URL, details, index_definition, - secret_columns, index_usage_summary, index_size_summary ) - SELECT 20 AS check_id, - MAX(i.index_sanity_id) AS index_sanity_id, - 100 AS Priority, - 'Index Hoarder' AS findings_group, - 'Many NC indexes on a single table' AS finding, - [database_name] AS [Database Name], - N'http://BrentOzar.com/go/IndexHoarder' AS URL, - CAST (COUNT(*) AS NVARCHAR(30)) + ' NC indexes on ' + i.db_schema_object_name AS details, - i.db_schema_object_name + ' (' + CAST (COUNT(*) AS NVARCHAR(30)) + ' indexes)' AS index_definition, - '' AS secret_columns, - REPLACE(CONVERT(NVARCHAR(30),CAST(SUM(total_reads) AS MONEY), 1), N'.00', N'') + N' reads (ALL); ' - + REPLACE(CONVERT(NVARCHAR(30),CAST(SUM(user_updates) AS MONEY), 1), N'.00', N'') + N' writes (ALL); ', - REPLACE(CONVERT(NVARCHAR(30),CAST(MAX(total_rows) AS MONEY), 1), N'.00', N'') + N' rows (MAX)' - + CASE WHEN SUM(total_reserved_MB) > 1024 THEN - N'; ' + CAST(CAST(SUM(total_reserved_MB)/1024. AS NUMERIC(29,1)) AS NVARCHAR(30)) + 'GB (ALL)' - WHEN SUM(total_reserved_MB) > 0 THEN - N'; ' + CAST(CAST(SUM(total_reserved_MB) AS NUMERIC(29,1)) AS NVARCHAR(30)) + 'MB (ALL)' - ELSE '' - END AS index_size_summary - FROM #IndexSanity i - JOIN #IndexSanitySize ip ON i.index_sanity_id = ip.index_sanity_id - WHERE index_id NOT IN ( 0, 1 ) - AND NOT (@GetAllDatabases = 1 OR @Mode = 0) - GROUP BY db_schema_object_name, [i].[database_name] - HAVING COUNT(*) >= 7 - ORDER BY i.db_schema_object_name DESC OPTION ( RECOMPILE ); - - IF @Filter = 1 /*@Filter=1 is "ignore unusued" */ - BEGIN - RAISERROR(N'Skipping checks on unused indexes (21 and 22) because @Filter=1', 0,1) WITH NOWAIT; - END - ELSE /*Otherwise, go ahead and do the checks*/ - BEGIN - RAISERROR(N'check_id 21: >=5 percent of indexes are unused. Yes, 5 is an arbitrary number.', 0,1) WITH NOWAIT; - DECLARE @percent_NC_indexes_unused NUMERIC(29,1); - DECLARE @NC_indexes_unused_reserved_MB NUMERIC(29,1); - - SELECT @percent_NC_indexes_unused =( 100.00 * SUM(CASE WHEN total_reads = 0 THEN 1 - ELSE 0 - END) ) / COUNT(*) , - @NC_indexes_unused_reserved_MB = SUM(CASE WHEN total_reads = 0 THEN sz.total_reserved_MB - ELSE 0 - END) - FROM #IndexSanity i - JOIN #IndexSanitySize sz ON i.index_sanity_id = sz.index_sanity_id - WHERE index_id NOT IN ( 0, 1 ) - AND i.is_unique = 0 - /*Skipping tables created in the last week, or modified in past 2 days*/ - AND i.create_date >= DATEADD(dd,-7,GETDATE()) - AND i.modify_date > DATEADD(dd,-2,GETDATE()) - OPTION ( RECOMPILE ); - - IF @percent_NC_indexes_unused >= 5 - INSERT #BlitzIndexResults ( check_id, index_sanity_id, Priority, findings_group, finding, [database_name], URL, details, index_definition, - secret_columns, index_usage_summary, index_size_summary ) - SELECT 21 AS check_id, - MAX(i.index_sanity_id) AS index_sanity_id, - 150 AS Priority, - N'Index Hoarder' AS findings_group, - N'More than 5 percent NC indexes are unused' AS finding, - [database_name] AS [Database Name], - N'http://BrentOzar.com/go/IndexHoarder' AS URL, - CAST (@percent_NC_indexes_unused AS NVARCHAR(30)) + N' percent NC indexes (' + CAST(COUNT(*) AS NVARCHAR(10)) + N') unused. ' + - N'These take up ' + CAST (@NC_indexes_unused_reserved_MB AS NVARCHAR(30)) + N'MB of space.' AS details, - i.database_name + ' (' + CAST (COUNT(*) AS NVARCHAR(30)) + N' indexes)' AS index_definition, - '' AS secret_columns, - CAST(SUM(total_reads) AS NVARCHAR(256)) + N' reads (ALL); ' - + CAST(SUM([user_updates]) AS NVARCHAR(256)) + N' writes (ALL)' AS index_usage_summary, - - REPLACE(CONVERT(NVARCHAR(30),CAST(MAX([total_rows]) AS MONEY), 1), '.00', '') + N' rows (MAX)' - + CASE WHEN SUM(total_reserved_MB) > 1024 THEN - N'; ' + CAST(CAST(SUM(total_reserved_MB)/1024. AS NUMERIC(29,1)) AS NVARCHAR(30)) + 'GB (ALL)' - WHEN SUM(total_reserved_MB) > 0 THEN - N'; ' + CAST(CAST(SUM(total_reserved_MB) AS NUMERIC(29,1)) AS NVARCHAR(30)) + 'MB (ALL)' - ELSE '' - END AS index_size_summary - FROM #IndexSanity i - JOIN #IndexSanitySize sz ON i.index_sanity_id = sz.index_sanity_id - WHERE index_id NOT IN ( 0, 1 ) - AND i.is_unique = 0 - AND total_reads = 0 - AND NOT (@GetAllDatabases = 1 OR @Mode = 0) - /*Skipping tables created in the last week, or modified in past 2 days*/ - AND i.create_date >= DATEADD(dd,-7,GETDATE()) - AND i.modify_date > DATEADD(dd,-2,GETDATE()) - GROUP BY i.database_name - OPTION ( RECOMPILE ); - - RAISERROR(N'check_id 22: NC indexes with 0 reads. (Borderline) and >= 10,000 writes', 0,1) WITH NOWAIT; - INSERT #BlitzIndexResults ( check_id, index_sanity_id, Priority, findings_group, finding, [database_name], URL, details, index_definition, - secret_columns, index_usage_summary, index_size_summary ) - SELECT 22 AS check_id, - i.index_sanity_id, - 100 AS Priority, - N'Index Hoarder' AS findings_group, - N'Unused NC index with High Writes' AS finding, - [database_name] AS [Database Name], - N'http://BrentOzar.com/go/IndexHoarder' AS URL, - N'0 reads: ' + i.db_schema_object_indexid AS details, - i.index_definition, - i.secret_columns, - i.index_usage_summary, - sz.index_size_summary - FROM #IndexSanity AS i - JOIN #IndexSanitySize AS sz ON i.index_sanity_id = sz.index_sanity_id - WHERE i.total_reads=0 - AND i.user_updates >= 10000 - AND i.index_id NOT IN (0,1) /*NCs only*/ - AND i.is_unique = 0 - AND sz.total_reserved_MB >= CASE WHEN (@GetAllDatabases = 1 OR @Mode = 0) THEN @ThresholdMB ELSE sz.total_reserved_MB END - ORDER BY i.db_schema_object_indexid - OPTION ( RECOMPILE ); - END /*end checks only run when @Filter <> 1*/ - - RAISERROR(N'check_id 23: Indexes with 7 or more columns. (Borderline)', 0,1) WITH NOWAIT; - INSERT #BlitzIndexResults ( check_id, index_sanity_id, Priority, findings_group, finding, [database_name], URL, details, index_definition, - secret_columns, index_usage_summary, index_size_summary ) - SELECT 23 AS check_id, - i.index_sanity_id, - 150 AS Priority, - N'Index Hoarder' AS findings_group, - N'Borderline: Wide indexes (7 or more columns)' AS finding, - [database_name] AS [Database Name], - N'http://BrentOzar.com/go/IndexHoarder' AS URL, - CAST(count_key_columns + count_included_columns AS NVARCHAR(10)) + ' columns on ' - + i.db_schema_object_indexid AS details, i.index_definition, - i.secret_columns, - i.index_usage_summary, - sz.index_size_summary - FROM #IndexSanity AS i - JOIN #IndexSanitySize AS sz ON i.index_sanity_id = sz.index_sanity_id - WHERE ( count_key_columns + count_included_columns ) >= 7 - AND NOT (@GetAllDatabases = 1 OR @Mode = 0) - OPTION ( RECOMPILE ); - - RAISERROR(N'check_id 24: Wide clustered indexes (> 3 columns or > 16 bytes).', 0,1) WITH NOWAIT; - WITH count_columns AS ( - SELECT database_id, [object_id], - SUM(CASE max_length WHEN -1 THEN 0 ELSE max_length END) AS sum_max_length - FROM #IndexColumns ic - WHERE index_id IN (1,0) /*Heap or clustered only*/ - AND key_ordinal > 0 - GROUP BY database_id, object_id - ) - INSERT #BlitzIndexResults ( check_id, index_sanity_id, Priority, findings_group, finding, [database_name], URL, details, index_definition, - secret_columns, index_usage_summary, index_size_summary ) - SELECT 24 AS check_id, - i.index_sanity_id, - 150 AS Priority, - N'Index Hoarder' AS findings_group, - N'Wide clustered index (> 3 columns OR > 16 bytes)' AS finding, - [database_name] AS [Database Name], - N'http://BrentOzar.com/go/IndexHoarder' AS URL, - CAST (i.count_key_columns AS NVARCHAR(10)) + N' columns with potential size of ' - + CAST(cc.sum_max_length AS NVARCHAR(10)) - + N' bytes in clustered index:' + i.db_schema_object_name - + N'. ' + - (SELECT CAST(COUNT(*) AS NVARCHAR(23)) FROM #IndexSanity i2 - WHERE i2.[object_id]=i.[object_id] AND i2.database_id = i.database_id AND i2.index_id <> 1 - AND i2.is_disabled=0 AND i2.is_hypothetical=0) - + N' NC indexes on the table.' - AS details, - i.index_definition, - secret_columns, - i.index_usage_summary, - ip.index_size_summary - FROM #IndexSanity i - JOIN #IndexSanitySize ip ON i.index_sanity_id = ip.index_sanity_id - JOIN count_columns AS cc ON i.[object_id]=cc.[object_id] - AND i.database_id = cc.database_id - WHERE index_id = 1 /* clustered only */ - AND NOT (@GetAllDatabases = 1 OR @Mode = 0) - AND - (count_key_columns > 3 /*More than three key columns.*/ - OR cc.sum_max_length > 16 /*More than 16 bytes in key */) - AND i.is_CX_columnstore = 0 - ORDER BY i.db_schema_object_name DESC OPTION ( RECOMPILE ); - - RAISERROR(N'check_id 25: Addicted to nullable columns.', 0,1) WITH NOWAIT; - WITH count_columns AS ( - SELECT [object_id], - [database_id], - [schema_name], - SUM(CASE is_nullable WHEN 1 THEN 0 ELSE 1 END) AS non_nullable_columns, - COUNT(*) AS total_columns - FROM #IndexColumns ic - WHERE index_id IN (1,0) /*Heap or clustered only*/ - GROUP BY [object_id], - [database_id], - [schema_name] - ) - INSERT #BlitzIndexResults ( check_id, index_sanity_id, Priority, findings_group, finding, [database_name], URL, details, index_definition, - secret_columns, index_usage_summary, index_size_summary ) - SELECT 25 AS check_id, - i.index_sanity_id, - 200 AS Priority, - N'Index Hoarder' AS findings_group, - N'Addicted to nulls' AS finding, - [database_name] AS [Database Name], - N'http://BrentOzar.com/go/IndexHoarder' AS URL, - i.db_schema_object_name - + N' allows null in ' + CAST((total_columns-non_nullable_columns) AS NVARCHAR(10)) - + N' of ' + CAST(total_columns AS NVARCHAR(10)) - + N' columns.' AS details, - i.index_definition, - secret_columns, - ISNULL(i.index_usage_summary,''), - ISNULL(ip.index_size_summary,'') - FROM #IndexSanity i - JOIN #IndexSanitySize ip ON i.index_sanity_id = ip.index_sanity_id - JOIN count_columns AS cc ON i.[object_id]=cc.[object_id] - AND cc.database_id = ip.database_id - AND cc.[schema_name] = ip.[schema_name] - WHERE i.index_id IN (1,0) - AND NOT (@GetAllDatabases = 1 OR @Mode = 0) - AND cc.non_nullable_columns < 2 - AND cc.total_columns > 3 - ORDER BY i.db_schema_object_name DESC OPTION ( RECOMPILE ); - - RAISERROR(N'check_id 26: Wide tables (35+ cols or > 2000 non-LOB bytes).', 0,1) WITH NOWAIT; - WITH count_columns AS ( - SELECT [object_id], - [database_id], - [schema_name], - SUM(CASE max_length WHEN -1 THEN 1 ELSE 0 END) AS count_lob_columns, - SUM(CASE max_length WHEN -1 THEN 0 ELSE max_length END) AS sum_max_length, - COUNT(*) AS total_columns - FROM #IndexColumns ic - WHERE index_id IN (1,0) /*Heap or clustered only*/ - GROUP BY [object_id], - [database_id], - [schema_name] - ) - INSERT #BlitzIndexResults ( check_id, index_sanity_id, Priority, findings_group, finding, [database_name], URL, details, index_definition, - secret_columns, index_usage_summary, index_size_summary ) - SELECT 26 AS check_id, - i.index_sanity_id, - 150 AS Priority, - N'Index Hoarder' AS findings_group, - N'Wide tables: 35+ cols or > 2000 non-LOB bytes' AS finding, - [database_name] AS [Database Name], - N'http://BrentOzar.com/go/IndexHoarder' AS URL, - i.db_schema_object_name - + N' has ' + CAST((total_columns) AS NVARCHAR(10)) - + N' total columns with a max possible width of ' + CAST(sum_max_length AS NVARCHAR(10)) - + N' bytes.' + - CASE WHEN count_lob_columns > 0 THEN CAST((count_lob_columns) AS NVARCHAR(10)) - + ' columns are LOB types.' ELSE '' - END - AS details, - i.index_definition, - secret_columns, - ISNULL(i.index_usage_summary,''), - ISNULL(ip.index_size_summary,'') - FROM #IndexSanity i - JOIN #IndexSanitySize ip ON i.index_sanity_id = ip.index_sanity_id - JOIN count_columns AS cc ON i.[object_id]=cc.[object_id] - AND cc.database_id = i.database_id - AND cc.[schema_name] = i.[schema_name] - WHERE i.index_id IN (1,0) - AND NOT (@GetAllDatabases = 1 OR @Mode = 0) - AND - (cc.total_columns >= 35 OR - cc.sum_max_length >= 2000) - ORDER BY i.db_schema_object_name DESC OPTION ( RECOMPILE ); - - RAISERROR(N'check_id 27: Addicted to strings.', 0,1) WITH NOWAIT; - WITH count_columns AS ( - SELECT [object_id], - [database_id], - [schema_name], - SUM(CASE WHEN system_type_name IN ('varchar','nvarchar','char') OR max_length=-1 THEN 1 ELSE 0 END) AS string_or_LOB_columns, - COUNT(*) AS total_columns - FROM #IndexColumns ic - WHERE index_id IN (1,0) /*Heap or clustered only*/ - GROUP BY [object_id], - [database_id], - [schema_name] - ) - INSERT #BlitzIndexResults ( check_id, index_sanity_id, Priority, findings_group, finding, [database_name], URL, details, index_definition, - secret_columns, index_usage_summary, index_size_summary ) - SELECT 27 AS check_id, - i.index_sanity_id, - 200 AS Priority, - N'Index Hoarder' AS findings_group, - N'Addicted to strings' AS finding, - [database_name] AS [Database Name], - N'http://BrentOzar.com/go/IndexHoarder' AS URL, - i.db_schema_object_name - + N' uses string or LOB types for ' + CAST((string_or_LOB_columns) AS NVARCHAR(10)) - + N' of ' + CAST(total_columns AS NVARCHAR(10)) - + N' columns. Check if data types are valid.' AS details, - i.index_definition, - secret_columns, - ISNULL(i.index_usage_summary,''), - ISNULL(ip.index_size_summary,'') - FROM #IndexSanity i - JOIN #IndexSanitySize ip ON i.index_sanity_id = ip.index_sanity_id - JOIN count_columns AS cc ON i.[object_id]=cc.[object_id] - AND cc.database_id = i.database_id - AND cc.[schema_name] = i.[schema_name] - CROSS APPLY (SELECT cc.total_columns - string_or_LOB_columns AS non_string_or_lob_columns) AS calc1 - WHERE i.index_id IN (1,0) - AND NOT (@GetAllDatabases = 1 OR @Mode = 0) - AND calc1.non_string_or_lob_columns <= 1 - AND cc.total_columns > 3 - ORDER BY i.db_schema_object_name DESC OPTION ( RECOMPILE ); - - RAISERROR(N'check_id 28: Non-unique clustered index.', 0,1) WITH NOWAIT; - INSERT #BlitzIndexResults ( check_id, index_sanity_id, Priority, findings_group, finding, [database_name], URL, details, index_definition, - secret_columns, index_usage_summary, index_size_summary ) - SELECT 28 AS check_id, - i.index_sanity_id, - 100 AS Priority, - N'Index Hoarder' AS findings_group, - N'Non-Unique clustered index' AS finding, - [database_name] AS [Database Name], - N'http://BrentOzar.com/go/IndexHoarder' AS URL, - N'Uniquifiers will be required! Clustered index: ' + i.db_schema_object_name - + N' and all NC indexes. ' + - (SELECT CAST(COUNT(*) AS NVARCHAR(23)) FROM #IndexSanity i2 - WHERE i2.[object_id]=i.[object_id] AND i2.database_id = i.database_id AND i2.index_id <> 1 - AND i2.is_disabled=0 AND i2.is_hypothetical=0) - + N' NC indexes on the table.' - AS details, - i.index_definition, - secret_columns, - i.index_usage_summary, - ip.index_size_summary - FROM #IndexSanity i - JOIN #IndexSanitySize ip ON i.index_sanity_id = ip.index_sanity_id - WHERE index_id = 1 /* clustered only */ - AND NOT (@GetAllDatabases = 1 OR @Mode = 0) - AND is_unique=0 /* not unique */ - AND is_CX_columnstore=0 /* not a clustered columnstore-- no unique option on those */ - ORDER BY i.db_schema_object_name DESC OPTION ( RECOMPILE ) - - RAISERROR(N'check_id 29: NC indexes with 0 reads. (Borderline) and < 10,000 writes', 0,1) WITH NOWAIT; - INSERT #BlitzIndexResults ( check_id, index_sanity_id, Priority, findings_group, finding, [database_name], URL, details, index_definition, - secret_columns, index_usage_summary, index_size_summary ) - SELECT 22 AS check_id, - i.index_sanity_id, - 150 AS Priority, - N'Index Hoarder' AS findings_group, - N'Unused NC index with Low Writes' AS finding, - [database_name] AS [Database Name], - N'http://BrentOzar.com/go/IndexHoarder' AS URL, - N'0 reads: ' + i.db_schema_object_indexid AS details, - i.index_definition, - i.secret_columns, - i.index_usage_summary, - sz.index_size_summary - FROM #IndexSanity AS i - JOIN #IndexSanitySize AS sz ON i.index_sanity_id = sz.index_sanity_id - WHERE i.total_reads=0 - AND i.user_updates < 10000 - AND i.index_id NOT IN (0,1) /*NCs only*/ - AND i.is_unique = 0 - AND sz.total_reserved_MB >= CASE WHEN (@GetAllDatabases = 1 OR @Mode = 0) THEN @ThresholdMB ELSE sz.total_reserved_MB END - ORDER BY i.db_schema_object_indexid - OPTION ( RECOMPILE ); - - END - ---------------------------------------- - --Feature-Phobic Indexes: Check_id 30-39 - ---------------------------------------- - BEGIN - RAISERROR(N'check_id 30: No indexes with includes', 0,1) WITH NOWAIT; - /* This does not work the way you'd expect with @GetAllDatabases = 1. For details: - https://github.com/BrentOzarULTD/SQL-Server-First-Responder-Kit/issues/825 - */ - - SELECT database_name, - SUM(CASE WHEN count_included_columns > 0 THEN 1 ELSE 0 END) AS number_indexes_with_includes, - 100.* SUM(CASE WHEN count_included_columns > 0 THEN 1 ELSE 0 END) / ( 1.0 * COUNT(*) ) AS percent_indexes_with_includes - INTO #index_includes - FROM #IndexSanity - GROUP BY database_name; - - IF NOT (@Mode = 0) - INSERT #BlitzIndexResults ( check_id, index_sanity_id, Priority, findings_group, finding, [database_name], URL, details, index_definition, - secret_columns, index_usage_summary, index_size_summary ) - SELECT 30 AS check_id, - NULL AS index_sanity_id, - 250 AS Priority, - N'Feature-Phobic Indexes' AS findings_group, - database_name AS [Database Name], - N'No indexes use includes' AS finding, 'http://BrentOzar.com/go/IndexFeatures' AS URL, - N'No indexes use includes' AS details, - database_name + N' (Entire database)' AS index_definition, - N'' AS secret_columns, - N'N/A' AS index_usage_summary, - N'N/A' AS index_size_summary - FROM #index_includes - WHERE number_indexes_with_includes = 0 - OPTION ( RECOMPILE ); - - RAISERROR(N'check_id 31: < 3 percent of indexes have includes', 0,1) WITH NOWAIT; - IF NOT (@Mode = 0) - INSERT #BlitzIndexResults ( check_id, index_sanity_id, Priority, findings_group, finding, [database_name], URL, details, index_definition, - secret_columns, index_usage_summary, index_size_summary ) - SELECT 31 AS check_id, - NULL AS index_sanity_id, - 150 AS Priority, - N'Feature-Phobic Indexes' AS findings_group, - N'Borderline: Includes are used in < 3% of indexes' AS findings, - database_name AS [Database Name], - N'http://BrentOzar.com/go/IndexFeatures' AS URL, - N'Only ' + CAST(percent_indexes_with_includes AS NVARCHAR(20)) + '% of indexes have includes' AS details, - N'Entire database' AS index_definition, - N'' AS secret_columns, - N'N/A' AS index_usage_summary, - N'N/A' AS index_size_summary - FROM #index_includes - WHERE number_indexes_with_includes > 0 AND percent_indexes_with_includes <= 3 - OPTION ( RECOMPILE ); - - RAISERROR(N'check_id 32: filtered indexes and indexed views', 0,1) WITH NOWAIT; - - IF NOT (@Mode = 0) - INSERT #BlitzIndexResults ( check_id, index_sanity_id, Priority, findings_group, finding, [database_name], URL, details, index_definition, - secret_columns, index_usage_summary, index_size_summary ) - SELECT DISTINCT - 32 AS check_id, - NULL AS index_sanity_id, - 250 AS Priority, - N'Feature-Phobic Indexes' AS findings_group, - N'Borderline: No filtered indexes or indexed views exist' AS finding, - i.database_name AS [Database Name], - N'http://BrentOzar.com/go/IndexFeatures' AS URL, - N'These are NOT always needed-- but do you know when you would use them?' AS details, - i.database_name + N' (Entire database)' AS index_definition, - N'' AS secret_columns, - N'N/A' AS index_usage_summary, - N'N/A' AS index_size_summary - FROM #IndexSanity i - WHERE i.database_name NOT IN ( - SELECT database_name - FROM #IndexSanity - WHERE filter_definition <> '' ) - AND i.database_name NOT IN ( - SELECT database_name - FROM #IndexSanity - WHERE is_indexed_view = 1 ) - OPTION ( RECOMPILE ); - END; - - RAISERROR(N'check_id 33: Potential filtered indexes based on column names.', 0,1) WITH NOWAIT; - - INSERT #BlitzIndexResults ( check_id, index_sanity_id, Priority, findings_group, finding, [database_name], URL, details, index_definition, - secret_columns, index_usage_summary, index_size_summary ) - SELECT 33 AS check_id, - i.index_sanity_id AS index_sanity_id, - 250 AS Priority, - N'Feature-Phobic Indexes' AS findings_group, - N'Potential filtered index (based on column name)' AS finding, - [database_name] AS [Database Name], - N'http://BrentOzar.com/go/IndexFeatures' AS URL, - N'A column name in this index suggests it might be a candidate for filtering (is%, %archive%, %active%, %flag%)' AS details, - i.index_definition, - i.secret_columns, - i.index_usage_summary, - sz.index_size_summary - FROM #IndexColumns ic - JOIN #IndexSanity i ON ic.[object_id]=i.[object_id] - AND ic.database_id =i.database_id - AND ic.schema_name = i.schema_name - AND ic.[index_id]=i.[index_id] - AND i.[index_id] > 1 /* non-clustered index */ - JOIN #IndexSanitySize AS sz ON i.index_sanity_id = sz.index_sanity_id - WHERE (column_name LIKE 'is%' - OR column_name LIKE '%archive%' - OR column_name LIKE '%active%' - OR column_name LIKE '%flag%') - AND NOT (@GetAllDatabases = 1 OR @Mode = 0) - OPTION ( RECOMPILE ); - - ---------------------------------------- - --Self Loathing Indexes : Check_id 40-49 - ---------------------------------------- - BEGIN - - RAISERROR(N'check_id 40: Fillfactor in nonclustered 80 percent or less', 0,1) WITH NOWAIT; - INSERT #BlitzIndexResults ( check_id, index_sanity_id, Priority, findings_group, finding, [database_name], URL, details, index_definition, - secret_columns, index_usage_summary, index_size_summary ) - SELECT 40 AS check_id, - i.index_sanity_id, - 100 AS Priority, - N'Self Loathing Indexes' AS findings_group, - N'Low Fill Factor: nonclustered index' AS finding, - [database_name] AS [Database Name], - N'http://BrentOzar.com/go/SelfLoathing' AS URL, - CAST(fill_factor AS NVARCHAR(10)) + N'% fill factor on ' + db_schema_object_indexid + N'. '+ - CASE WHEN (last_user_update IS NULL OR user_updates < 1) - THEN N'No writes have been made.' - ELSE - N'Last write was ' + CONVERT(NVARCHAR(16),last_user_update,121) + N' and ' + - CAST(user_updates AS NVARCHAR(25)) + N' updates have been made.' - END - AS details, - i.index_definition, - i.secret_columns, - i.index_usage_summary, - sz.index_size_summary - FROM #IndexSanity AS i - JOIN #IndexSanitySize AS sz ON i.index_sanity_id = sz.index_sanity_id - WHERE index_id > 1 - AND NOT (@GetAllDatabases = 1 OR @Mode = 0) - AND fill_factor BETWEEN 1 AND 80 OPTION ( RECOMPILE ); - - RAISERROR(N'check_id 40: Fillfactor in clustered 80 percent or less', 0,1) WITH NOWAIT; - INSERT #BlitzIndexResults ( check_id, index_sanity_id, Priority, findings_group, finding, [database_name], URL, details, index_definition, - secret_columns, index_usage_summary, index_size_summary ) - SELECT 40 AS check_id, - i.index_sanity_id, - 100 AS Priority, - N'Self Loathing Indexes' AS findings_group, - N'Low Fill Factor: clustered index' AS finding, - [database_name] AS [Database Name], - N'http://BrentOzar.com/go/SelfLoathing' AS URL, - N'Fill factor on ' + db_schema_object_indexid + N' is ' + CAST(fill_factor AS NVARCHAR(10)) + N'%. '+ - CASE WHEN (last_user_update IS NULL OR user_updates < 1) - THEN N'No writes have been made.' - ELSE - N'Last write was ' + CONVERT(NVARCHAR(16),last_user_update,121) + N' and ' + - CAST(user_updates AS NVARCHAR(25)) + N' updates have been made.' - END - AS details, - i.index_definition, - i.secret_columns, - i.index_usage_summary, - sz.index_size_summary - FROM #IndexSanity AS i - JOIN #IndexSanitySize AS sz ON i.index_sanity_id = sz.index_sanity_id - WHERE index_id = 1 - AND NOT (@GetAllDatabases = 1 OR @Mode = 0) - AND fill_factor BETWEEN 1 AND 80 OPTION ( RECOMPILE ); - - - RAISERROR(N'check_id 41: Hypothetical indexes ', 0,1) WITH NOWAIT; - INSERT #BlitzIndexResults ( check_id, index_sanity_id, Priority, findings_group, finding, [database_name], URL, details, index_definition, - secret_columns, index_usage_summary, index_size_summary ) - SELECT 41 AS check_id, - i.index_sanity_id, - 150 AS Priority, - N'Self Loathing Indexes' AS findings_group, - N'Hypothetical Index' AS finding, - [database_name] AS [Database Name], - N'http://BrentOzar.com/go/SelfLoathing' AS URL, - N'Hypothetical Index: ' + db_schema_object_indexid AS details, - i.index_definition, - i.secret_columns, - N'' AS index_usage_summary, - N'' AS index_size_summary - FROM #IndexSanity AS i - WHERE is_hypothetical = 1 - AND NOT (@GetAllDatabases = 1 OR @Mode = 0) - OPTION ( RECOMPILE ); - - - RAISERROR(N'check_id 42: Disabled indexes', 0,1) WITH NOWAIT; - --Note: disabled NC indexes will have O rows in #IndexSanitySize! - INSERT #BlitzIndexResults ( check_id, index_sanity_id, Priority, findings_group, finding, [database_name], URL, details, index_definition, - secret_columns, index_usage_summary, index_size_summary ) - SELECT 42 AS check_id, - index_sanity_id, - 150 AS Priority, - N'Self Loathing Indexes' AS findings_group, - N'Disabled Index' AS finding, - [database_name] AS [Database Name], - N'http://BrentOzar.com/go/SelfLoathing' AS URL, - N'Disabled Index:' + db_schema_object_indexid AS details, - i.index_definition, - i.secret_columns, - i.index_usage_summary, - 'DISABLED' AS index_size_summary - FROM #IndexSanity AS i - WHERE is_disabled = 1 - AND NOT (@GetAllDatabases = 1 OR @Mode = 0) - OPTION ( RECOMPILE ); - - RAISERROR(N'check_id 43: Heaps with forwarded records or deletes', 0,1) WITH NOWAIT; - WITH heaps_cte - AS ( SELECT [object_id], - [database_id], - [schema_name], - SUM(forwarded_fetch_count) AS forwarded_fetch_count, - SUM(leaf_delete_count) AS leaf_delete_count - FROM #IndexPartitionSanity - GROUP BY [object_id], - [database_id], - [schema_name] - HAVING SUM(forwarded_fetch_count) > 0 - OR SUM(leaf_delete_count) > 0) - INSERT #BlitzIndexResults ( check_id, index_sanity_id, Priority, findings_group, finding, [database_name], URL, details, index_definition, - secret_columns, index_usage_summary, index_size_summary ) - SELECT 43 AS check_id, - i.index_sanity_id, - 100 AS Priority, - N'Self Loathing Indexes' AS findings_group, - N'Heaps with forwarded records or deletes' AS finding, - [database_name] AS [Database Name], - N'http://BrentOzar.com/go/SelfLoathing' AS URL, - CAST(h.forwarded_fetch_count AS NVARCHAR(256)) + ' forwarded fetches, ' - + CAST(h.leaf_delete_count AS NVARCHAR(256)) + ' deletes against heap:' - + db_schema_object_indexid AS details, - i.index_definition, - i.secret_columns, - i.index_usage_summary, - sz.index_size_summary - FROM #IndexSanity i - JOIN heaps_cte h ON i.[object_id] = h.[object_id] - AND i.[database_id] = h.[database_id] - AND i.[schema_name] = h.[schema_name] - JOIN #IndexSanitySize sz ON i.index_sanity_id = sz.index_sanity_id - WHERE i.index_id = 0 - AND sz.total_reserved_MB >= CASE WHEN NOT (@GetAllDatabases = 1 OR @Mode = 4) THEN @ThresholdMB ELSE sz.total_reserved_MB END - OPTION ( RECOMPILE ); - - RAISERROR(N'check_id 44: Large Heaps with reads or writes.', 0,1) WITH NOWAIT; - WITH heaps_cte - AS ( SELECT [object_id], - [database_id], - [schema_name], - SUM(forwarded_fetch_count) AS forwarded_fetch_count, - SUM(leaf_delete_count) AS leaf_delete_count - FROM #IndexPartitionSanity - GROUP BY [object_id], - [database_id], - [schema_name] - HAVING SUM(forwarded_fetch_count) > 0 - OR SUM(leaf_delete_count) > 0) - INSERT #BlitzIndexResults ( check_id, index_sanity_id, Priority, findings_group, finding, [database_name], URL, details, index_definition, - secret_columns, index_usage_summary, index_size_summary ) - SELECT 44 AS check_id, - i.index_sanity_id, - 100 AS Priority, - N'Self Loathing Indexes' AS findings_group, - N'Large Active heap' AS finding, - [database_name] AS [Database Name], - N'http://BrentOzar.com/go/SelfLoathing' AS URL, - N'Should this table be a heap? ' + db_schema_object_indexid AS details, - i.index_definition, - 'N/A' AS secret_columns, - i.index_usage_summary, - sz.index_size_summary - FROM #IndexSanity i - LEFT JOIN heaps_cte h ON i.[object_id] = h.[object_id] - AND i.[database_id] = h.[database_id] - AND i.[schema_name] = h.[schema_name] - JOIN #IndexSanitySize sz ON i.index_sanity_id = sz.index_sanity_id - WHERE i.index_id = 0 - AND - (i.total_reads > 0 OR i.user_updates > 0) - AND sz.total_rows >= 100000 - AND h.[object_id] IS NULL /*don't duplicate the prior check.*/ - AND NOT (@GetAllDatabases = 1 OR @Mode = 0) - OPTION ( RECOMPILE ); - - RAISERROR(N'check_id 45: Medium Heaps with reads or writes.', 0,1) WITH NOWAIT; - WITH heaps_cte - AS ( SELECT [object_id], - [database_id], - [schema_name], - SUM(forwarded_fetch_count) AS forwarded_fetch_count, - SUM(leaf_delete_count) AS leaf_delete_count - FROM #IndexPartitionSanity - GROUP BY [object_id], - [database_id], - [schema_name] - HAVING SUM(forwarded_fetch_count) > 0 - OR SUM(leaf_delete_count) > 0) - INSERT #BlitzIndexResults ( check_id, index_sanity_id, Priority, findings_group, finding, [database_name], URL, details, index_definition, - secret_columns, index_usage_summary, index_size_summary ) - SELECT 45 AS check_id, - i.index_sanity_id, - 100 AS Priority, - N'Self Loathing Indexes' AS findings_group, - N'Medium Active heap' AS finding, - [database_name] AS [Database Name], - N'http://BrentOzar.com/go/SelfLoathing' AS URL, - N'Should this table be a heap? ' + db_schema_object_indexid AS details, - i.index_definition, - 'N/A' AS secret_columns, - i.index_usage_summary, - sz.index_size_summary - FROM #IndexSanity i - LEFT JOIN heaps_cte h ON i.[object_id] = h.[object_id] - AND i.[database_id] = h.[database_id] - AND i.[schema_name] = h.[schema_name] - JOIN #IndexSanitySize sz ON i.index_sanity_id = sz.index_sanity_id - WHERE i.index_id = 0 - AND - (i.total_reads > 0 OR i.user_updates > 0) - AND sz.total_rows >= 10000 AND sz.total_rows < 100000 - AND h.[object_id] IS NULL /*don't duplicate the prior check.*/ - AND NOT (@GetAllDatabases = 1 OR @Mode = 0) - OPTION ( RECOMPILE ); - - RAISERROR(N'check_id 46: Small Heaps with reads or writes.', 0,1) WITH NOWAIT; - WITH heaps_cte - AS ( SELECT [object_id], - [database_id], - [schema_name], - SUM(forwarded_fetch_count) AS forwarded_fetch_count, - SUM(leaf_delete_count) AS leaf_delete_count - FROM #IndexPartitionSanity - GROUP BY [object_id], - [database_id], - [schema_name] - HAVING SUM(forwarded_fetch_count) > 0 - OR SUM(leaf_delete_count) > 0) - INSERT #BlitzIndexResults ( check_id, index_sanity_id, Priority, findings_group, finding, [database_name], URL, details, index_definition, - secret_columns, index_usage_summary, index_size_summary ) - SELECT 46 AS check_id, - i.index_sanity_id, - 100 AS Priority, - N'Self Loathing Indexes' AS findings_group, - N'Small Active heap' AS finding, - [database_name] AS [Database Name], - N'http://BrentOzar.com/go/SelfLoathing' AS URL, - N'Should this table be a heap? ' + db_schema_object_indexid AS details, - i.index_definition, - 'N/A' AS secret_columns, - i.index_usage_summary, - sz.index_size_summary - FROM #IndexSanity i - LEFT JOIN heaps_cte h ON i.[object_id] = h.[object_id] - AND i.[database_id] = h.[database_id] - AND i.[schema_name] = h.[schema_name] - JOIN #IndexSanitySize sz ON i.index_sanity_id = sz.index_sanity_id - WHERE i.index_id = 0 - AND - (i.total_reads > 0 OR i.user_updates > 0) - AND sz.total_rows < 10000 - AND h.[object_id] IS NULL /*don't duplicate the prior check.*/ - AND NOT (@GetAllDatabases = 1 OR @Mode = 0) - OPTION ( RECOMPILE ); - - RAISERROR(N'check_id 47: Heap with a Nonclustered Primary Key', 0,1) WITH NOWAIT; - INSERT #BlitzIndexResults ( check_id, index_sanity_id, Priority, findings_group, finding, [database_name], URL, details, index_definition, - secret_columns, index_usage_summary, index_size_summary ) - SELECT 47 AS check_id, - i.index_sanity_id, - 100 AS Priority, - N'Self Loathing Indexes' AS findings_group, - N'Heap with a Nonclustered Primary Key' AS finding, - [database_name] AS [Database Name], - N'http://BrentOzar.com/go/SelfLoathing' AS URL, - db_schema_object_indexid + N' is a HEAP with a Nonclustered Primary Key' AS details, - i.index_definition, - i.secret_columns, - i.index_usage_summary, - sz.index_size_summary - FROM #IndexSanity i - JOIN #IndexSanitySize sz ON i.index_sanity_id = sz.index_sanity_id - WHERE i.index_type = 2 AND i.is_primary_key = 1 AND i.secret_columns LIKE '%RID%' - OPTION ( RECOMPILE ); - - END; - ---------------------------------------- - --Indexaphobia - --Missing indexes with value >= 5 million: : Check_id 50-59 - ---------------------------------------- - BEGIN - RAISERROR(N'check_id 50: Indexaphobia.', 0,1) WITH NOWAIT; - WITH index_size_cte - AS ( SELECT i.database_id, - i.schema_name, - i.[object_id], - MAX(i.index_sanity_id) AS index_sanity_id, - ISNULL(NULLIF(MAX(DATEDIFF(DAY, i.create_date, SYSDATETIME())), 0), 1) AS create_days, - ISNULL ( - CAST(SUM(CASE WHEN index_id NOT IN (0,1) THEN 1 ELSE 0 END) - AS NVARCHAR(30))+ N' NC indexes exist (' + - CASE WHEN SUM(CASE WHEN index_id NOT IN (0,1) THEN sz.total_reserved_MB ELSE 0 END) > 1024 - THEN CAST(CAST(SUM(CASE WHEN index_id NOT IN (0,1) THEN sz.total_reserved_MB ELSE 0 END )/1024. - - AS NUMERIC(29,1)) AS NVARCHAR(30)) + N'GB); ' - ELSE CAST(SUM(CASE WHEN index_id NOT IN (0,1) THEN sz.total_reserved_MB ELSE 0 END) - AS NVARCHAR(30)) + N'MB); ' - END + - CASE WHEN MAX(sz.[total_rows]) >= 922337203685477 THEN '>= 922,337,203,685,477' - ELSE REPLACE(CONVERT(NVARCHAR(30),CAST(MAX(sz.[total_rows]) AS MONEY), 1), '.00', '') - END + - + N' Estimated Rows;' - ,N'') AS index_size_summary - FROM #IndexSanity AS i - LEFT JOIN #IndexSanitySize AS sz ON i.index_sanity_id = sz.index_sanity_id AND i.database_id = sz.database_id - WHERE i.is_hypothetical = 0 - AND i.is_disabled = 0 - GROUP BY i.database_id, i.schema_name, i.[object_id]) - INSERT #BlitzIndexResults ( check_id, index_sanity_id, Priority, findings_group, finding, [database_name], URL, details, index_definition, - index_usage_summary, index_size_summary, create_tsql, more_info ) - - SELECT check_id, t.index_sanity_id, t.check_id, t.findings_group, t.finding, t.[Database Name], t.URL, t.details, t.[definition], - index_estimated_impact, t.index_size_summary, create_tsql, more_info - FROM - ( - SELECT ROW_NUMBER() OVER (ORDER BY mi.is_low, magic_benefit_number DESC) AS rownum, - 50 AS check_id, - sz.index_sanity_id, - 10 AS Priority, - N'Indexaphobia' AS findings_group, - N'High value missing index' + CASE mi.is_low - WHEN 0 THEN N' with High Impact' - WHEN 1 THEN N' with Low Impact' - END - AS finding, - [database_name] AS [Database Name], - N'http://BrentOzar.com/go/Indexaphobia' AS URL, - mi.[statement] + - N' Est. benefit per day: ' + - CASE WHEN magic_benefit_number >= 922337203685477 THEN '>= 922,337,203,685,477' - ELSE REPLACE(CONVERT(NVARCHAR(256),CAST(CAST( - (magic_benefit_number/@DaysUptime) - AS BIGINT) AS MONEY), 1), '.00', '') - END AS details, - missing_index_details AS [definition], - index_estimated_impact, - sz.index_size_summary, - mi.create_tsql, - mi.more_info, - magic_benefit_number, - mi.is_low - FROM #MissingIndexes mi - LEFT JOIN index_size_cte sz ON mi.[object_id] = sz.object_id - AND mi.database_id = sz.database_id - AND mi.schema_name = sz.schema_name - /* Minimum benefit threshold = 100k/day of uptime OR since table creation date, whichever is lower*/ - WHERE ( @Mode = 4 AND (magic_benefit_number / CASE WHEN sz.create_days < @DaysUptime THEN sz.create_days ELSE @DaysUptime END) >= 100000 ) - OR (magic_benefit_number / CASE WHEN sz.create_days < @DaysUptime THEN sz.create_days ELSE @DaysUptime END) >= 100000 - ) AS t - WHERE t.rownum <= CASE WHEN (@Mode <> 4) THEN 20 ELSE t.rownum END - ORDER BY t.is_low, magic_benefit_number DESC - - - END - ---------------------------------------- - --Abnormal Psychology : Check_id 60-79 - ---------------------------------------- - BEGIN - RAISERROR(N'check_id 60: XML indexes', 0,1) WITH NOWAIT; - INSERT #BlitzIndexResults ( check_id, index_sanity_id, Priority, findings_group, finding, [database_name], URL, details, index_definition, - secret_columns, index_usage_summary, index_size_summary ) - SELECT 60 AS check_id, - i.index_sanity_id, - 150 AS Priority, - N'Abnormal Psychology' AS findings_group, - N'XML Indexes' AS finding, - [database_name] AS [Database Name], - N'http://BrentOzar.com/go/AbnormalPsychology' AS URL, - i.db_schema_object_indexid AS details, - i.index_definition, - i.secret_columns, - N'' AS index_usage_summary, - ISNULL(sz.index_size_summary,'') AS index_size_summary - FROM #IndexSanity AS i - JOIN #IndexSanitySize sz ON i.index_sanity_id = sz.index_sanity_id - WHERE i.is_XML = 1 OPTION ( RECOMPILE ); - - RAISERROR(N'check_id 61: Columnstore indexes', 0,1) WITH NOWAIT; - INSERT #BlitzIndexResults ( check_id, index_sanity_id, Priority, findings_group, finding, [database_name], URL, details, index_definition, - secret_columns, index_usage_summary, index_size_summary ) - SELECT 61 AS check_id, - i.index_sanity_id, - 150 AS Priority, - N'Abnormal Psychology' AS findings_group, - CASE WHEN i.is_NC_columnstore=1 - THEN N'NC Columnstore Index' - ELSE N'Clustered Columnstore Index' - END AS finding, - [database_name] AS [Database Name], - N'http://BrentOzar.com/go/AbnormalPsychology' AS URL, - i.db_schema_object_indexid AS details, - i.index_definition, - i.secret_columns, - i.index_usage_summary, - ISNULL(sz.index_size_summary,'') AS index_size_summary - FROM #IndexSanity AS i - JOIN #IndexSanitySize sz ON i.index_sanity_id = sz.index_sanity_id - WHERE i.is_NC_columnstore = 1 OR i.is_CX_columnstore=1 - OPTION ( RECOMPILE ); - - - RAISERROR(N'check_id 62: Spatial indexes', 0,1) WITH NOWAIT; - INSERT #BlitzIndexResults ( check_id, index_sanity_id, Priority, findings_group, finding, [database_name], URL, details, index_definition, - secret_columns, index_usage_summary, index_size_summary ) - SELECT 62 AS check_id, - i.index_sanity_id, - 150 AS Priority, - N'Abnormal Psychology' AS findings_group, - N'Spatial indexes' AS finding, - [database_name] AS [Database Name], - N'http://BrentOzar.com/go/AbnormalPsychology' AS URL, - i.db_schema_object_indexid AS details, - i.index_definition, - i.secret_columns, - i.index_usage_summary, - ISNULL(sz.index_size_summary,'') AS index_size_summary - FROM #IndexSanity AS i - JOIN #IndexSanitySize sz ON i.index_sanity_id = sz.index_sanity_id - WHERE i.is_spatial = 1 OPTION ( RECOMPILE ); - - RAISERROR(N'check_id 63: Compressed indexes', 0,1) WITH NOWAIT; - INSERT #BlitzIndexResults ( check_id, index_sanity_id, Priority, findings_group, finding, [database_name], URL, details, index_definition, - secret_columns, index_usage_summary, index_size_summary ) - SELECT 63 AS check_id, - i.index_sanity_id, - 150 AS Priority, - N'Abnormal Psychology' AS findings_group, - N'Compressed indexes' AS finding, - [database_name] AS [Database Name], - N'http://BrentOzar.com/go/AbnormalPsychology' AS URL, - i.db_schema_object_indexid + N'. COMPRESSION: ' + sz.data_compression_desc AS details, - i.index_definition, - i.secret_columns, - i.index_usage_summary, - ISNULL(sz.index_size_summary,'') AS index_size_summary - FROM #IndexSanity AS i - JOIN #IndexSanitySize sz ON i.index_sanity_id = sz.index_sanity_id - WHERE sz.data_compression_desc LIKE '%PAGE%' OR sz.data_compression_desc LIKE '%ROW%' OPTION ( RECOMPILE ); - - RAISERROR(N'check_id 64: Partitioned', 0,1) WITH NOWAIT; - INSERT #BlitzIndexResults ( check_id, index_sanity_id, Priority, findings_group, finding, [database_name], URL, details, index_definition, - secret_columns, index_usage_summary, index_size_summary ) - SELECT 64 AS check_id, - i.index_sanity_id, - 150 AS Priority, - N'Abnormal Psychology' AS findings_group, - N'Partitioned indexes' AS finding, - [database_name] AS [Database Name], - N'http://BrentOzar.com/go/AbnormalPsychology' AS URL, - i.db_schema_object_indexid AS details, - i.index_definition, - i.secret_columns, - i.index_usage_summary, - ISNULL(sz.index_size_summary,'') AS index_size_summary - FROM #IndexSanity AS i - JOIN #IndexSanitySize sz ON i.index_sanity_id = sz.index_sanity_id - WHERE i.partition_key_column_name IS NOT NULL OPTION ( RECOMPILE ); - - RAISERROR(N'check_id 65: Non-Aligned Partitioned', 0,1) WITH NOWAIT; - INSERT #BlitzIndexResults ( check_id, index_sanity_id, Priority, findings_group, finding, [database_name], URL, details, index_definition, - secret_columns, index_usage_summary, index_size_summary ) - SELECT 65 AS check_id, - i.index_sanity_id, - 150 AS Priority, - N'Abnormal Psychology' AS findings_group, - N'Non-Aligned index on a partitioned table' AS finding, - i.[database_name] AS [Database Name], - N'http://BrentOzar.com/go/AbnormalPsychology' AS URL, - i.db_schema_object_indexid AS details, - i.index_definition, - i.secret_columns, - i.index_usage_summary, - ISNULL(sz.index_size_summary,'') AS index_size_summary - FROM #IndexSanity AS i - JOIN #IndexSanity AS iParent ON - i.[object_id]=iParent.[object_id] - AND i.database_id = iParent.database_id - AND i.schema_name = iParent.schema_name - AND iParent.index_id IN (0,1) /* could be a partitioned heap or clustered table */ - AND iParent.partition_key_column_name IS NOT NULL /* parent is partitioned*/ - JOIN #IndexSanitySize sz ON i.index_sanity_id = sz.index_sanity_id - WHERE i.partition_key_column_name IS NULL - OPTION ( RECOMPILE ); - - RAISERROR(N'check_id 66: Recently created tables/indexes (1 week)', 0,1) WITH NOWAIT; - INSERT #BlitzIndexResults ( check_id, index_sanity_id, Priority, findings_group, finding, [database_name], URL, details, index_definition, - secret_columns, index_usage_summary, index_size_summary ) - SELECT 66 AS check_id, - i.index_sanity_id, - 200 AS Priority, - N'Abnormal Psychology' AS findings_group, - N'Recently created tables/indexes (1 week)' AS finding, - [database_name] AS [Database Name], - N'http://BrentOzar.com/go/AbnormalPsychology' AS URL, - i.db_schema_object_indexid + N' was created on ' + - CONVERT(NVARCHAR(16),i.create_date,121) + - N'. Tables/indexes which are dropped/created regularly require special methods for index tuning.' - AS details, - i.index_definition, - i.secret_columns, - i.index_usage_summary, - ISNULL(sz.index_size_summary,'') AS index_size_summary - FROM #IndexSanity AS i - JOIN #IndexSanitySize sz ON i.index_sanity_id = sz.index_sanity_id - WHERE i.create_date >= DATEADD(dd,-7,GETDATE()) - AND NOT (@GetAllDatabases = 1 OR @Mode = 0) - OPTION ( RECOMPILE ); - - RAISERROR(N'check_id 67: Recently modified tables/indexes (2 days)', 0,1) WITH NOWAIT; - INSERT #BlitzIndexResults ( check_id, index_sanity_id, Priority, findings_group, finding, [database_name], URL, details, index_definition, - secret_columns, index_usage_summary, index_size_summary ) - SELECT 67 AS check_id, - i.index_sanity_id, - 200 AS Priority, - N'Abnormal Psychology' AS findings_group, - N'Recently modified tables/indexes (2 days)' AS finding, - [database_name] AS [Database Name], - N'http://BrentOzar.com/go/AbnormalPsychology' AS URL, - i.db_schema_object_indexid + N' was modified on ' + - CONVERT(NVARCHAR(16),i.modify_date,121) + - N'. A large amount of recently modified indexes may mean a lot of rebuilds are occurring each night.' - AS details, - i.index_definition, - i.secret_columns, - i.index_usage_summary, - ISNULL(sz.index_size_summary,'') AS index_size_summary - FROM #IndexSanity AS i - JOIN #IndexSanitySize sz ON i.index_sanity_id = sz.index_sanity_id - WHERE i.modify_date > DATEADD(dd,-2,GETDATE()) - AND NOT (@GetAllDatabases = 1 OR @Mode = 0) - AND /*Exclude recently created tables.*/ - i.create_date < DATEADD(dd,-7,GETDATE()) - OPTION ( RECOMPILE ); - - RAISERROR(N'check_id 68: Identity columns within 30 percent of the end of range', 0,1) WITH NOWAIT; - -- Allowed Ranges: - --int -2,147,483,648 to 2,147,483,647 - --smallint -32,768 to 32,768 - --tinyint 0 to 255 - - INSERT #BlitzIndexResults ( check_id, index_sanity_id, Priority, findings_group, finding, [database_name], URL, details, index_definition, - secret_columns, index_usage_summary, index_size_summary ) - SELECT 68 AS check_id, - i.index_sanity_id, - 200 AS Priority, - N'Abnormal Psychology' AS findings_group, - N'Identity column within ' + - CAST (calc1.percent_remaining AS NVARCHAR(256)) - + N' percent end of range' AS finding, - [database_name] AS [Database Name], - N'http://BrentOzar.com/go/AbnormalPsychology' AS URL, - i.db_schema_object_name + N'.' + QUOTENAME(ic.column_name) - + N' is an identity with type ' + ic.system_type_name - + N', last value of ' - + ISNULL(REPLACE(CONVERT(NVARCHAR(256),CAST(CAST(ic.last_value AS BIGINT) AS MONEY), 1), '.00', ''),N'NULL') - + N', seed of ' - + ISNULL(REPLACE(CONVERT(NVARCHAR(256),CAST(CAST(ic.seed_value AS BIGINT) AS MONEY), 1), '.00', ''),N'NULL') - + N', increment of ' + CAST(ic.increment_value AS NVARCHAR(256)) - + N', and range of ' + - CASE ic.system_type_name WHEN 'int' THEN N'+/- 2,147,483,647' - WHEN 'smallint' THEN N'+/- 32,768' - WHEN 'tinyint' THEN N'0 to 255' - END - AS details, - i.index_definition, - secret_columns, - ISNULL(i.index_usage_summary,''), - ISNULL(ip.index_size_summary,'') - FROM #IndexSanity i - JOIN #IndexColumns ic ON - i.object_id=ic.object_id - AND i.database_id = ic.database_id - AND i.schema_name = ic.schema_name - AND i.index_id IN (0,1) /* heaps and cx only */ - AND ic.is_identity=1 - AND ic.system_type_name IN ('tinyint', 'smallint', 'int') - JOIN #IndexSanitySize ip ON i.index_sanity_id = ip.index_sanity_id - CROSS APPLY ( - SELECT CAST(CASE WHEN ic.increment_value >= 0 - THEN - CASE ic.system_type_name - WHEN 'int' THEN (2147483647 - (ISNULL(ic.last_value,ic.seed_value) + ic.increment_value)) / 2147483647.*100 - WHEN 'smallint' THEN (32768 - (ISNULL(ic.last_value,ic.seed_value) + ic.increment_value)) / 32768.*100 - WHEN 'tinyint' THEN ( 255 - (ISNULL(ic.last_value,ic.seed_value) + ic.increment_value)) / 255.*100 - ELSE 999 - END - ELSE --ic.increment_value is negative - CASE ic.system_type_name - WHEN 'int' THEN ABS(-2147483647 - (ISNULL(ic.last_value,ic.seed_value) + ic.increment_value)) / 2147483647.*100 - WHEN 'smallint' THEN ABS(-32768 - (ISNULL(ic.last_value,ic.seed_value) + ic.increment_value)) / 32768.*100 - WHEN 'tinyint' THEN ABS( 0 - (ISNULL(ic.last_value,ic.seed_value) + ic.increment_value)) / 255.*100 - ELSE -1 - END - END AS NUMERIC(5,1)) AS percent_remaining - ) AS calc1 - WHERE i.index_id IN (1,0) - AND calc1.percent_remaining <= 30 - UNION ALL - SELECT 68 AS check_id, - i.index_sanity_id, - 200 AS Priority, - N'Abnormal Psychology' AS findings_group, - N'Identity column using a negative seed or increment other than 1' AS finding, - [database_name] AS [Database Name], - N'http://BrentOzar.com/go/AbnormalPsychology' AS URL, - i.db_schema_object_name + N'.' + QUOTENAME(ic.column_name) - + N' is an identity with type ' + ic.system_type_name - + N', last value of ' - + ISNULL(REPLACE(CONVERT(NVARCHAR(256),CAST(CAST(ic.last_value AS BIGINT) AS MONEY), 1), '.00', ''),N'NULL') - + N', seed of ' - + ISNULL(REPLACE(CONVERT(NVARCHAR(256),CAST(CAST(ic.seed_value AS BIGINT) AS MONEY), 1), '.00', ''),N'NULL') - + N', increment of ' + CAST(ic.increment_value AS NVARCHAR(256)) - + N', and range of ' + - CASE ic.system_type_name WHEN 'int' THEN N'+/- 2,147,483,647' - WHEN 'smallint' THEN N'+/- 32,768' - WHEN 'tinyint' THEN N'0 to 255' - END - AS details, - i.index_definition, - secret_columns, - ISNULL(i.index_usage_summary,''), - ISNULL(ip.index_size_summary,'') - FROM #IndexSanity i - JOIN #IndexColumns ic ON - i.object_id=ic.object_id - AND i.database_id = ic.database_id - AND i.schema_name = ic.schema_name - AND i.index_id IN (0,1) /* heaps and cx only */ - AND ic.is_identity=1 - AND ic.system_type_name IN ('tinyint', 'smallint', 'int') - JOIN #IndexSanitySize ip ON i.index_sanity_id = ip.index_sanity_id - WHERE i.index_id IN (1,0) - AND (ic.seed_value < 0 OR ic.increment_value <> 1) - ORDER BY finding, details DESC OPTION ( RECOMPILE ); - - RAISERROR(N'check_id 69: Column collation does not match database collation', 0,1) WITH NOWAIT; - WITH count_columns AS ( - SELECT [object_id], - database_id, - schema_name, - COUNT(*) AS column_count - FROM #IndexColumns ic - WHERE index_id IN (1,0) /*Heap or clustered only*/ - AND collation_name <> @collation - GROUP BY [object_id], - database_id, - schema_name - ) - INSERT #BlitzIndexResults ( check_id, index_sanity_id, Priority, findings_group, finding, [database_name], URL, details, index_definition, - secret_columns, index_usage_summary, index_size_summary ) - SELECT 69 AS check_id, - i.index_sanity_id, - 150 AS Priority, - N'Abnormal Psychology' AS findings_group, - N'Column collation does not match database collation' AS finding, - [database_name] AS [Database Name], - N'http://BrentOzar.com/go/AbnormalPsychology' AS URL, - i.db_schema_object_name - + N' has ' + CAST(column_count AS NVARCHAR(20)) - + N' column' + CASE WHEN column_count > 1 THEN 's' ELSE '' END - + N' with a different collation than the db collation of ' - + @collation AS details, - i.index_definition, - secret_columns, - ISNULL(i.index_usage_summary,''), - ISNULL(ip.index_size_summary,'') - FROM #IndexSanity i - JOIN #IndexSanitySize ip ON i.index_sanity_id = ip.index_sanity_id - JOIN count_columns AS cc ON i.[object_id]=cc.[object_id] - AND cc.database_id = i.database_id - AND cc.schema_name = i.schema_name - WHERE i.index_id IN (1,0) - AND NOT (@GetAllDatabases = 1 OR @Mode = 0) - ORDER BY i.db_schema_object_name DESC OPTION ( RECOMPILE ); - - RAISERROR(N'check_id 70: Replicated columns', 0,1) WITH NOWAIT; - WITH count_columns AS ( - SELECT [object_id], - database_id, - schema_name, - COUNT(*) AS column_count, - SUM(CASE is_replicated WHEN 1 THEN 1 ELSE 0 END) AS replicated_column_count - FROM #IndexColumns ic - WHERE index_id IN (1,0) /*Heap or clustered only*/ - GROUP BY object_id, - database_id, - schema_name - ) - INSERT #BlitzIndexResults ( check_id, index_sanity_id, Priority, findings_group, finding, [database_name], URL, details, index_definition, - secret_columns, index_usage_summary, index_size_summary ) - SELECT 70 AS check_id, - i.index_sanity_id, - 200 AS Priority, - N'Abnormal Psychology' AS findings_group, - N'Replicated columns' AS finding, - [database_name] AS [Database Name], - N'http://BrentOzar.com/go/AbnormalPsychology' AS URL, - i.db_schema_object_name - + N' has ' + CAST(replicated_column_count AS NVARCHAR(20)) - + N' out of ' + CAST(column_count AS NVARCHAR(20)) - + N' column' + CASE WHEN column_count > 1 THEN 's' ELSE '' END - + N' in one or more publications.' - AS details, - i.index_definition, - secret_columns, - ISNULL(i.index_usage_summary,''), - ISNULL(ip.index_size_summary,'') - FROM #IndexSanity i - JOIN #IndexSanitySize ip ON i.index_sanity_id = ip.index_sanity_id - JOIN count_columns AS cc ON i.[object_id]=cc.[object_id] - AND i.database_id = cc.database_id - AND i.schema_name = cc.schema_name - WHERE i.index_id IN (1,0) - AND replicated_column_count > 0 - AND NOT (@GetAllDatabases = 1 OR @Mode = 0) - ORDER BY i.db_schema_object_name DESC OPTION ( RECOMPILE ); - - RAISERROR(N'check_id 71: Cascading updates or cascading deletes.', 0,1) WITH NOWAIT; - INSERT #BlitzIndexResults ( check_id, index_sanity_id, Priority, findings_group, finding, [database_name], URL, details, index_definition, - secret_columns, index_usage_summary, index_size_summary, more_info ) - SELECT 71 AS check_id, - NULL AS index_sanity_id, - 150 AS Priority, - N'Abnormal Psychology' AS findings_group, - N'Cascading Updates or Deletes' AS finding, - [database_name] AS [Database Name], - N'http://BrentOzar.com/go/AbnormalPsychology' AS URL, - N'Foreign Key ' + foreign_key_name + - N' on ' + QUOTENAME(parent_object_name) + N'(' + LTRIM(parent_fk_columns) + N')' - + N' referencing ' + QUOTENAME(referenced_object_name) + N'(' + LTRIM(referenced_fk_columns) + N')' - + N' has settings:' - + CASE [delete_referential_action_desc] WHEN N'NO_ACTION' THEN N'' ELSE N' ON DELETE ' +[delete_referential_action_desc] END - + CASE [update_referential_action_desc] WHEN N'NO_ACTION' THEN N'' ELSE N' ON UPDATE ' + [update_referential_action_desc] END - AS details, - [fk].[database_name] - AS index_definition, - N'N/A' AS secret_columns, - N'N/A' AS index_usage_summary, - N'N/A' AS index_size_summary, - (SELECT TOP 1 more_info FROM #IndexSanity i WHERE i.object_id=fk.parent_object_id AND i.database_id = fk.database_id AND i.schema_name = fk.schema_name) - AS more_info - FROM #ForeignKeys fk - WHERE ([delete_referential_action_desc] <> N'NO_ACTION' - OR [update_referential_action_desc] <> N'NO_ACTION') - AND NOT (@GetAllDatabases = 1 OR @Mode = 0) - - RAISERROR(N'check_id 72: Columnstore indexes with Trace Flag 834', 0,1) WITH NOWAIT; - IF EXISTS (SELECT * FROM #IndexSanity WHERE index_type IN (5,6)) - AND EXISTS (SELECT * FROM #TraceStatus WHERE TraceFlag = 834 AND status = 1) - BEGIN - INSERT #BlitzIndexResults ( check_id, index_sanity_id, Priority, findings_group, finding, [database_name], URL, details, index_definition, - secret_columns, index_usage_summary, index_size_summary ) - SELECT 72 AS check_id, - i.index_sanity_id, - 150 AS Priority, - N'Abnormal Psychology' AS findings_group, - 'Columnstore Indexes are being used in conjunction with trace flag 834. Visit the link to see why this can be a bad idea' AS finding, - [database_name] AS [Database Name], - N'https://support.microsoft.com/en-us/kb/3210239' AS URL, - i.db_schema_object_indexid AS details, - i.index_definition, - i.secret_columns, - i.index_usage_summary, - ISNULL(sz.index_size_summary,'') AS index_size_summary - FROM #IndexSanity AS i - JOIN #IndexSanitySize sz ON i.index_sanity_id = sz.index_sanity_id - WHERE i.index_type IN (5,6) - OPTION ( RECOMPILE ) - END - - END - - ---------------------------------------- - --Workaholics: Check_id 80-89 - ---------------------------------------- - BEGIN - - RAISERROR(N'check_id 80: Most scanned indexes (index_usage_stats)', 0,1) WITH NOWAIT; - INSERT #BlitzIndexResults ( check_id, index_sanity_id, Priority, findings_group, finding, [database_name], URL, details, index_definition, - secret_columns, index_usage_summary, index_size_summary ) - - --Workaholics according to index_usage_stats - --This isn't perfect: it mentions the number of scans present in a plan - --A "scan" isn't necessarily a full scan, but hey, we gotta do the best with what we've got. - --in the case of things like indexed views, the operator might be in the plan but never executed - SELECT TOP 5 - 80 AS check_id, - i.index_sanity_id AS index_sanity_id, - 200 AS Priority, - N'Workaholics' AS findings_group, - N'Scan-a-lots (index_usage_stats)' AS finding, - [database_name] AS [Database Name], - N'http://BrentOzar.com/go/Workaholics' AS URL, - REPLACE(CONVERT( NVARCHAR(50),CAST(i.user_scans AS MONEY),1),'.00','') - + N' scans against ' + i.db_schema_object_indexid - + N'. Latest scan: ' + ISNULL(CAST(i.last_user_scan AS NVARCHAR(128)),'?') + N'. ' - + N'ScanFactor=' + CAST(((i.user_scans * iss.total_reserved_MB)/1000000.) AS NVARCHAR(256)) AS details, - ISNULL(i.key_column_names_with_sort_order,'N/A') AS index_definition, - ISNULL(i.secret_columns,'') AS secret_columns, - i.index_usage_summary AS index_usage_summary, - iss.index_size_summary AS index_size_summary - FROM #IndexSanity i - JOIN #IndexSanitySize iss ON i.index_sanity_id=iss.index_sanity_id - WHERE ISNULL(i.user_scans,0) > 0 - AND NOT (@GetAllDatabases = 1 OR @Mode = 0) - ORDER BY i.user_scans * iss.total_reserved_MB DESC; - - RAISERROR(N'check_id 81: Top recent accesses (op stats)', 0,1) WITH NOWAIT; - INSERT #BlitzIndexResults ( check_id, index_sanity_id, Priority, findings_group, finding, [database_name], URL, details, index_definition, - secret_columns, index_usage_summary, index_size_summary ) - --Workaholics according to index_operational_stats - --This isn't perfect either: range_scan_count contains full scans, partial scans, even seeks in nested loop ops - --But this can help bubble up some most-accessed tables - SELECT TOP 5 - 81 AS check_id, - i.index_sanity_id AS index_sanity_id, - 200 AS Priority, - N'Workaholics' AS findings_group, - N'Top recent accesses (index_op_stats)' AS finding, - [database_name] AS [Database Name], - N'http://BrentOzar.com/go/Workaholics' AS URL, - ISNULL(REPLACE( - CONVERT(NVARCHAR(50),CAST((iss.total_range_scan_count + iss.total_singleton_lookup_count) AS MONEY),1), - N'.00',N'') - + N' uses of ' + i.db_schema_object_indexid + N'. ' - + REPLACE(CONVERT(NVARCHAR(50), CAST(iss.total_range_scan_count AS MONEY),1),N'.00',N'') + N' scans or seeks. ' - + REPLACE(CONVERT(NVARCHAR(50), CAST(iss.total_singleton_lookup_count AS MONEY), 1),N'.00',N'') + N' singleton lookups. ' - + N'OpStatsFactor=' + CAST(((((iss.total_range_scan_count + iss.total_singleton_lookup_count) * iss.total_reserved_MB))/1000000.) AS VARCHAR(256)),'') AS details, - ISNULL(i.key_column_names_with_sort_order,'N/A') AS index_definition, - ISNULL(i.secret_columns,'') AS secret_columns, - i.index_usage_summary AS index_usage_summary, - iss.index_size_summary AS index_size_summary - FROM #IndexSanity i - JOIN #IndexSanitySize iss ON i.index_sanity_id=iss.index_sanity_id - WHERE (ISNULL(iss.total_range_scan_count,0) > 0 OR ISNULL(iss.total_singleton_lookup_count,0) > 0) - AND NOT (@GetAllDatabases = 1 OR @Mode = 0) - ORDER BY ((iss.total_range_scan_count + iss.total_singleton_lookup_count) * iss.total_reserved_MB) DESC; - - - END - - ---------------------------------------- - --Statistics Info: Check_id 90-99 - ---------------------------------------- - BEGIN - - RAISERROR(N'check_id 90: Outdated statistics', 0,1) WITH NOWAIT; - INSERT #BlitzIndexResults ( check_id, Priority, findings_group, finding, [database_name], URL, details, index_definition, - secret_columns, index_usage_summary, index_size_summary ) - SELECT 90 AS check_id, - 200 AS Priority, - 'Functioning Statistaholics' AS findings_group, - 'Statistic Abandonment Issues', - s.database_name, - '' AS URL, - 'Statistics on this table were last updated ' + - CASE s.last_statistics_update WHEN NULL THEN N' NEVER ' - ELSE CONVERT(NVARCHAR(20), s.last_statistics_update) + - ' have had ' + CONVERT(NVARCHAR(100), s.modification_counter) + - ' modifications in that time, which is ' + - CONVERT(NVARCHAR(100), s.percent_modifications) + - '% of the table.' - END AS details, - QUOTENAME(database_name) + '.' + QUOTENAME(s.schema_name) + '.' + QUOTENAME(s.table_name) + '.' + QUOTENAME(s.index_name) + '.' + QUOTENAME(s.statistics_name) + '.' + QUOTENAME(s.column_names) AS index_definition, - 'N/A' AS secret_columns, - 'N/A' AS index_usage_summary, - 'N/A' AS index_size_summary - FROM #Statistics AS s - WHERE s.last_statistics_update <= CONVERT(DATETIME, GETDATE() - 7) - AND s.percent_modifications >= 10. - AND s.rows >= 10000 - - RAISERROR(N'check_id 91: Statistics with a low sample rate', 0,1) WITH NOWAIT; - INSERT #BlitzIndexResults ( check_id, Priority, findings_group, finding, [database_name], URL, details, index_definition, - secret_columns, index_usage_summary, index_size_summary ) - SELECT 91 AS check_id, - 200 AS Priority, - 'Functioning Statistaholics' AS findings_group, - 'Antisocial Samples', - s.database_name, - '' AS URL, - 'Only ' + CONVERT(NVARCHAR(100), s.percent_sampled) + '% of the rows were sampled during the last statistics update. This may lead to poor cardinality estimates.' AS details, - QUOTENAME(database_name) + '.' + QUOTENAME(s.schema_name) + '.' + QUOTENAME(s.table_name) + '.' + QUOTENAME(s.index_name) + '.' + QUOTENAME(s.statistics_name) + '.' + QUOTENAME(s.column_names) AS index_definition, - 'N/A' AS secret_columns, - 'N/A' AS index_usage_summary, - 'N/A' AS index_size_summary - FROM #Statistics AS s - WHERE s.rows_sampled < 1. - AND s.rows >= 10000 - - RAISERROR(N'check_id 92: Statistics with NO RECOMPUTE', 0,1) WITH NOWAIT; - INSERT #BlitzIndexResults ( check_id, Priority, findings_group, finding, [database_name], URL, details, index_definition, - secret_columns, index_usage_summary, index_size_summary ) - SELECT 92 AS check_id, - 200 AS Priority, - 'Functioning Statistaholics' AS findings_group, - 'Cyberphobic Samples', - s.database_name, - '' AS URL, - 'The statistic ' + QUOTENAME(s.statistics_name) + ' is set to not recompute. This can be helpful if data is really skewed, but harmful if you expect automatic statistics updates.' AS details, - QUOTENAME(database_name) + '.' + QUOTENAME(s.schema_name) + '.' + QUOTENAME(s.table_name) + '.' + QUOTENAME(s.index_name) + '.' + QUOTENAME(s.statistics_name) + '.' + QUOTENAME(s.column_names) AS index_definition, - 'N/A' AS secret_columns, - 'N/A' AS index_usage_summary, - 'N/A' AS index_size_summary - FROM #Statistics AS s - WHERE s.no_recompute = 1 - - RAISERROR(N'check_id 93: Statistics with filters', 0,1) WITH NOWAIT; - INSERT #BlitzIndexResults ( check_id, Priority, findings_group, finding, [database_name], URL, details, index_definition, - secret_columns, index_usage_summary, index_size_summary ) - SELECT 93 AS check_id, - 200 AS Priority, - 'Functioning Statistaholics' AS findings_group, - 'Filter Fixation', - s.database_name, - '' AS URL, - 'The statistic ' + QUOTENAME(s.statistics_name) + ' is filtered on [' + s.filter_definition + ']. It could be part of a filtered index, or just a filtered statistic. This is purely informational.' AS details, - QUOTENAME(database_name) + '.' + QUOTENAME(s.schema_name) + '.' + QUOTENAME(s.table_name) + '.' + QUOTENAME(s.index_name) + '.' + QUOTENAME(s.statistics_name) + '.' + QUOTENAME(s.column_names) AS index_definition, - 'N/A' AS secret_columns, - 'N/A' AS index_usage_summary, - 'N/A' AS index_size_summary - FROM #Statistics AS s - WHERE s.has_filter = 1 - - END - - ---------------------------------------- - --Computed Column Info: Check_id 99-109 - ---------------------------------------- - BEGIN - - RAISERROR(N'check_id 99: Computed Columns That Reference Functions', 0,1) WITH NOWAIT; - INSERT #BlitzIndexResults ( check_id, Priority, findings_group, finding, [database_name], URL, details, index_definition, - secret_columns, index_usage_summary, index_size_summary ) - SELECT 99 AS check_id, - 50 AS Priority, - 'Cold Calculators' AS findings_group, - 'Serial Forcer' AS finding, - cc.database_name, - '' AS URL, - 'The computed column ' + QUOTENAME(cc.column_name) + ' on ' + QUOTENAME(cc.schema_name) + '.' + QUOTENAME(cc.table_name) + ' is based on ' + cc.definition - + '. That indicates it may reference a scalar function, or a CLR function with data access, which can cause all queries and maintenance to run serially.' AS details, - cc.column_definition, - 'N/A' AS secret_columns, - 'N/A' AS index_usage_summary, - 'N/A' AS index_size_summary - FROM #ComputedColumns AS cc - WHERE cc.is_function = 1 - - RAISERROR(N'check_id 100: Computed Columns that are not Persisted.', 0,1) WITH NOWAIT; - INSERT #BlitzIndexResults ( check_id, Priority, findings_group, finding, [database_name], URL, details, index_definition, - secret_columns, index_usage_summary, index_size_summary ) - SELECT 100 AS check_id, - 200 AS Priority, - 'Cold Calculators' AS findings_group, - 'Definition Defeatists' AS finding, - cc.database_name, - '' AS URL, - 'The computed column ' + QUOTENAME(cc.column_name) + ' on ' + QUOTENAME(cc.schema_name) + '.' + QUOTENAME(cc.table_name) + ' is not persisted, which means it will be calculated when a query runs.' + - 'You can change this with the following command, if the definition is deterministic: ALTER TABLE ' + QUOTENAME(cc.schema_name) + '.' + QUOTENAME(cc.table_name) + ' ALTER COLUMN ' + cc.column_name + - ' ADD PERSISTED' AS details, - cc.column_definition, - 'N/A' AS secret_columns, - 'N/A' AS index_usage_summary, - 'N/A' AS index_size_summary - FROM #ComputedColumns AS cc - WHERE cc.is_persisted = 0 - - ---------------------------------------- - --Temporal Table Info: Check_id 110-119 - ---------------------------------------- - RAISERROR(N'check_id 110: Temporal Tables.', 0,1) WITH NOWAIT; - INSERT #BlitzIndexResults ( check_id, Priority, findings_group, finding, [database_name], URL, details, index_definition, - secret_columns, index_usage_summary, index_size_summary ) - - SELECT 110 AS check_id, - 200 AS Priority, - 'Temporal Tables' AS findings_group, - 'Obsessive Compulsive Tables', - t.database_name, - '' AS URL, - 'The table ' + QUOTENAME(t.schema_name) + '.' + QUOTENAME(t.table_name) + ' is a temporal table, with rows versioned in ' - + QUOTENAME(t.history_schema_name) + '.' + QUOTENAME(t.history_table_name) + ' on History columns ' + QUOTENAME(t.start_column_name) + ' and ' + QUOTENAME(t.end_column_name) + '.' - AS details, - '' AS index_definition, - 'N/A' AS secret_columns, - 'N/A' AS index_usage_summary, - 'N/A' AS index_size_summary - FROM #TemporalTables AS t - - - - END - - RAISERROR(N'Insert a row to help people find help', 0,1) WITH NOWAIT; - IF DATEDIFF(MM, @VersionDate, GETDATE()) > 6 - BEGIN - INSERT #BlitzIndexResults ( Priority, check_id, findings_group, finding, URL, details, index_definition, - index_usage_summary, index_size_summary ) - VALUES ( -1, 0 , - 'Outdated sp_BlitzIndex', 'sp_BlitzIndex is Over 6 Months Old', 'http://FirstResponderKit.org/', - 'Fine wine gets better with age, but this ' + @ScriptVersionName + ' is more like bad cheese. Time to get a new one.', - N'',N'',N'' - ); - END - - IF EXISTS(SELECT * FROM #BlitzIndexResults) - BEGIN - INSERT #BlitzIndexResults ( Priority, check_id, findings_group, finding, URL, details, index_definition, - index_usage_summary, index_size_summary ) - VALUES ( -1, 0 , - @ScriptVersionName, - CASE WHEN @GetAllDatabases = 1 THEN N'All Databases' ELSE N'Database ' + QUOTENAME(@DatabaseName) + N' as of ' + CONVERT(NVARCHAR(16),GETDATE(),121) END, - N'From Your Community Volunteers' , N'http://FirstResponderKit.org' , - N'' - , N'',N'' - ); - END - ELSE IF @Mode = 0 OR (@GetAllDatabases = 1 AND @Mode <> 4) - BEGIN - INSERT #BlitzIndexResults ( Priority, check_id, findings_group, finding, URL, details, index_definition, - index_usage_summary, index_size_summary ) - VALUES ( -1, 0 , - @ScriptVersionName, - CASE WHEN @GetAllDatabases = 1 THEN N'All Databases' ELSE N'Database ' + QUOTENAME(@DatabaseName) + N' as of ' + CONVERT(NVARCHAR(16),GETDATE(),121) END, - N'From Your Community Volunteers' , N'http://FirstResponderKit.org' , - N'' - , N'',N'' - ); - INSERT #BlitzIndexResults ( Priority, check_id, findings_group, finding, URL, details, index_definition, - index_usage_summary, index_size_summary ) - VALUES ( 1, 0 , - 'No Major Problems Found', - 'Nice Work!', - 'http://FirstResponderKit.org', 'Consider running with @Mode = 4 in individual databases (not all) for more detailed diagnostics.', 'The new default Mode 0 only looks for very serious index issues.', '', '' - ); - - END - ELSE - BEGIN - INSERT #BlitzIndexResults ( Priority, check_id, findings_group, finding, URL, details, index_definition, - index_usage_summary, index_size_summary ) - VALUES ( -1, 0 , - @ScriptVersionName, - CASE WHEN @GetAllDatabases = 1 THEN N'All Databases' ELSE N'Database ' + QUOTENAME(@DatabaseName) + N' as of ' + CONVERT(NVARCHAR(16),GETDATE(),121) END, - N'From Your Community Volunteers' , N'http://www.BrentOzar.com/BlitzIndex' , - N'' - , N'',N'' - ); - INSERT #BlitzIndexResults ( Priority, check_id, findings_group, finding, URL, details, index_definition, - index_usage_summary, index_size_summary ) - VALUES ( 1, 0 , - 'No Problems Found', - 'Nice job! Or more likely, you have a nearly empty database.', - 'http://FirstResponderKit.org', 'Time to go read some blog posts.', '', '', '' - ); - - END - - RAISERROR(N'Returning results.', 0,1) WITH NOWAIT; - - /*Return results.*/ - IF (@Mode = 0) - BEGIN - - SELECT Priority, ISNULL(br.findings_group,N'') + - CASE WHEN ISNULL(br.finding,N'') <> N'' THEN N': ' ELSE N'' END - + br.finding AS [Finding], - br.[database_name] AS [Database Name], - br.details AS [Details: schema.table.index(indexid)], - br.index_definition AS [Definition: [Property]] ColumnName {datatype maxbytes}], - ISNULL(br.secret_columns,'') AS [Secret Columns], - br.index_usage_summary AS [Usage], - br.index_size_summary AS [Size], - COALESCE(br.more_info,sn.more_info,'') AS [More Info], - br.URL, - COALESCE(br.create_tsql,ts.create_tsql,'') AS [Create TSQL] - FROM #BlitzIndexResults br - LEFT JOIN #IndexSanity sn ON - br.index_sanity_id=sn.index_sanity_id - LEFT JOIN #IndexCreateTsql ts ON - br.index_sanity_id=ts.index_sanity_id - WHERE br.check_id IN (0, 1, 11, 22, 43, 68, 50, 60, 61, 62, 63, 64, 65, 72) - ORDER BY br.Priority ASC, br.check_id ASC, br.blitz_result_id ASC, br.findings_group ASC - OPTION (RECOMPILE); - - END - ELSE IF (@Mode = 4) - SELECT Priority, ISNULL(br.findings_group,N'') + - CASE WHEN ISNULL(br.finding,N'') <> N'' THEN N': ' ELSE N'' END - + br.finding AS [Finding], - br.[database_name] AS [Database Name], - br.details AS [Details: schema.table.index(indexid)], - br.index_definition AS [Definition: [Property]] ColumnName {datatype maxbytes}], - ISNULL(br.secret_columns,'') AS [Secret Columns], - br.index_usage_summary AS [Usage], - br.index_size_summary AS [Size], - COALESCE(br.more_info,sn.more_info,'') AS [More Info], - br.URL, - COALESCE(br.create_tsql,ts.create_tsql,'') AS [Create TSQL] - FROM #BlitzIndexResults br - LEFT JOIN #IndexSanity sn ON - br.index_sanity_id=sn.index_sanity_id - LEFT JOIN #IndexCreateTsql ts ON - br.index_sanity_id=ts.index_sanity_id - ORDER BY br.Priority ASC, br.check_id ASC, br.blitz_result_id ASC, br.findings_group ASC - OPTION (RECOMPILE); - - END; /* End @Mode=0 or 4 (diagnose)*/ - ELSE IF @Mode=1 /*Summarize*/ - BEGIN - --This mode is to give some overall stats on the database. - RAISERROR(N'@Mode=1, we are summarizing.', 0,1) WITH NOWAIT; - - SELECT DB_NAME(i.database_id) AS [Database Name], - CAST((COUNT(*)) AS NVARCHAR(256)) AS [Number Objects], - CAST(CAST(SUM(sz.total_reserved_MB)/ - 1024. AS NUMERIC(29,1)) AS NVARCHAR(500)) AS [All GB], - CAST(CAST(SUM(sz.total_reserved_LOB_MB)/ - 1024. AS NUMERIC(29,1)) AS NVARCHAR(500)) AS [LOB GB], - CAST(CAST(SUM(sz.total_reserved_row_overflow_MB)/ - 1024. AS NUMERIC(29,1)) AS NVARCHAR(500)) AS [Row Overflow GB], - CAST(SUM(CASE WHEN index_id=1 THEN 1 ELSE 0 END)AS NVARCHAR(50)) AS [Clustered Tables], - CAST(SUM(CASE WHEN index_id=1 THEN sz.total_reserved_MB ELSE 0 END) - /1024. AS NUMERIC(29,1)) AS [Clustered Tables GB], - SUM(CASE WHEN index_id NOT IN (0,1) THEN 1 ELSE 0 END) AS [NC Indexes], - CAST(SUM(CASE WHEN index_id NOT IN (0,1) THEN sz.total_reserved_MB ELSE 0 END) - /1024. AS NUMERIC(29,1)) AS [NC Indexes GB], - CASE WHEN SUM(CASE WHEN index_id NOT IN (0,1) THEN sz.total_reserved_MB ELSE 0 END) > 0 THEN - CAST(SUM(CASE WHEN index_id IN (0,1) THEN sz.total_reserved_MB ELSE 0 END) - / SUM(CASE WHEN index_id NOT IN (0,1) THEN sz.total_reserved_MB ELSE 0 END) AS NUMERIC(29,1)) - ELSE 0 END AS [ratio table: NC Indexes], - SUM(CASE WHEN index_id=0 THEN 1 ELSE 0 END) AS [Heaps], - CAST(SUM(CASE WHEN index_id=0 THEN sz.total_reserved_MB ELSE 0 END) - /1024. AS NUMERIC(29,1)) AS [Heaps GB], - SUM(CASE WHEN index_id IN (0,1) AND partition_key_column_name IS NOT NULL THEN 1 ELSE 0 END) AS [Partitioned Tables], - SUM(CASE WHEN index_id NOT IN (0,1) AND partition_key_column_name IS NOT NULL THEN 1 ELSE 0 END) AS [Partitioned NCs], - CAST(SUM(CASE WHEN partition_key_column_name IS NOT NULL THEN sz.total_reserved_MB ELSE 0 END)/1024. AS NUMERIC(29,1)) AS [Partitioned GB], - SUM(CASE WHEN filter_definition <> '' THEN 1 ELSE 0 END) AS [Filtered Indexes], - SUM(CASE WHEN is_indexed_view=1 THEN 1 ELSE 0 END) AS [Indexed Views], - MAX(total_rows) AS [Max Row Count], - CAST(MAX(CASE WHEN index_id IN (0,1) THEN sz.total_reserved_MB ELSE 0 END) - /1024. AS NUMERIC(29,1)) AS [Max Table GB], - CAST(MAX(CASE WHEN index_id NOT IN (0,1) THEN sz.total_reserved_MB ELSE 0 END) - /1024. AS NUMERIC(29,1)) AS [Max NC Index GB], - SUM(CASE WHEN index_id IN (0,1) AND sz.total_reserved_MB > 1024 THEN 1 ELSE 0 END) AS [Count Tables > 1GB], - SUM(CASE WHEN index_id IN (0,1) AND sz.total_reserved_MB > 10240 THEN 1 ELSE 0 END) AS [Count Tables > 10GB], - SUM(CASE WHEN index_id IN (0,1) AND sz.total_reserved_MB > 102400 THEN 1 ELSE 0 END) AS [Count Tables > 100GB], - SUM(CASE WHEN index_id NOT IN (0,1) AND sz.total_reserved_MB > 1024 THEN 1 ELSE 0 END) AS [Count NCs > 1GB], - SUM(CASE WHEN index_id NOT IN (0,1) AND sz.total_reserved_MB > 10240 THEN 1 ELSE 0 END) AS [Count NCs > 10GB], - SUM(CASE WHEN index_id NOT IN (0,1) AND sz.total_reserved_MB > 102400 THEN 1 ELSE 0 END) AS [Count NCs > 100GB], - MIN(create_date) AS [Oldest Create Date], - MAX(create_date) AS [Most Recent Create Date], - MAX(modify_date) AS [Most Recent Modify Date], - 1 AS [Display Order] - FROM #IndexSanity AS i - --left join here so we don't lose disabled nc indexes - LEFT JOIN #IndexSanitySize AS sz - ON i.index_sanity_id=sz.index_sanity_id - GROUP BY DB_NAME(i.database_id) - UNION ALL - SELECT CASE WHEN @GetAllDatabases = 1 THEN N'All Databases' ELSE N'Database ' + N' as of ' + CONVERT(NVARCHAR(16),GETDATE(),121) END, - @ScriptVersionName, - N'From Your Community Volunteers' , - N'http://FirstResponderKit.org' , - N'', - NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL, - NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL, - NULL,NULL,0 AS display_order - ORDER BY [Display Order] ASC - OPTION (RECOMPILE); - - END /* End @Mode=1 (summarize)*/ - ELSE IF @Mode=2 /*Index Detail*/ - BEGIN - --This mode just spits out all the detail without filters. - --This supports slicing AND dicing in Excel - RAISERROR(N'@Mode=2, here''s the details on existing indexes.', 0,1) WITH NOWAIT; - - - /* Checks if @OutputServerName is populated with a valid linked server, and that the database name specified is valid */ - DECLARE @ValidOutputServer BIT - DECLARE @ValidOutputLocation BIT - DECLARE @LinkedServerDBCheck NVARCHAR(2000) - DECLARE @ValidLinkedServerDB INT - DECLARE @tmpdbchk table (cnt int) - DECLARE @StringToExecute NVARCHAR(MAX); - - IF @OutputServerName IS NOT NULL - BEGIN - IF (SUBSTRING(@OutputTableName, 2, 1) = '#') - BEGIN - RAISERROR('Due to the nature of temporary tables, outputting to a linked server requires a permanent table.', 16, 0); - END - ELSE IF EXISTS (SELECT server_id FROM sys.servers WHERE QUOTENAME([name]) = @OutputServerName) - BEGIN - SET @LinkedServerDBCheck = 'SELECT 1 WHERE EXISTS (SELECT * FROM '+@OutputServerName+'.master.sys.databases WHERE QUOTENAME([name]) = '''+@OutputDatabaseName+''')' - INSERT INTO @tmpdbchk EXEC sys.sp_executesql @LinkedServerDBCheck - SET @ValidLinkedServerDB = (SELECT COUNT(*) FROM @tmpdbchk) - IF (@ValidLinkedServerDB > 0) - BEGIN - SET @ValidOutputServer = 1 - SET @ValidOutputLocation = 1 - END - ELSE - RAISERROR('The specified database was not found on the output server', 16, 0) - END - ELSE - BEGIN - RAISERROR('The specified output server was not found', 16, 0) - END - END - ELSE - BEGIN - IF (SUBSTRING(@OutputTableName, 2, 2) = '##') - BEGIN - SET @StringToExecute = N' IF (OBJECT_ID(''[tempdb].[dbo].@@@OutputTableName@@@'') IS NOT NULL) DROP TABLE @@@OutputTableName@@@'; - SET @StringToExecute = REPLACE(@StringToExecute, '@@@OutputTableName@@@', @OutputTableName) - EXEC(@StringToExecute); - - SET @OutputServerName = QUOTENAME(CAST(SERVERPROPERTY('ServerName') AS NVARCHAR(128))) - SET @OutputDatabaseName = '[tempdb]'; - SET @OutputSchemaName = '[dbo]'; - SET @ValidOutputLocation = 1; - END - ELSE IF (SUBSTRING(@OutputTableName, 2, 1) = '#') - BEGIN - RAISERROR('Due to the nature of Dymamic SQL, only global (i.e. double pound (##)) temp tables are supported for @OutputTableName', 16, 0) - END - ELSE IF @OutputDatabaseName IS NOT NULL - AND @OutputSchemaName IS NOT NULL - AND @OutputTableName IS NOT NULL - AND EXISTS ( SELECT * - FROM sys.databases - WHERE QUOTENAME([name]) = @OutputDatabaseName) - BEGIN - SET @ValidOutputLocation = 1 - SET @OutputServerName = QUOTENAME(CAST(SERVERPROPERTY('ServerName') AS NVARCHAR(128))) - END - ELSE IF @OutputDatabaseName IS NOT NULL - AND @OutputSchemaName IS NOT NULL - AND @OutputTableName IS NOT NULL - AND NOT EXISTS ( SELECT * - FROM sys.databases - WHERE QUOTENAME([name]) = @OutputDatabaseName) - BEGIN - RAISERROR('The specified output database was not found on this server', 16, 0) - END - ELSE - BEGIN - SET @ValidOutputLocation = 0 - END - END - - /* @OutputTableName lets us export the results to a permanent table */ - DECLARE @RunID UNIQUEIDENTIFIER; - SET @RunID = NEWID(); - - IF (@ValidOutputLocation = 1 AND COALESCE(@OutputServerName, @OutputDatabaseName, @OutputSchemaName, @OutputTableName) IS NOT NULL) - BEGIN - DECLARE @TableExists BIT; - DECLARE @SchemaExists BIT; - SET @StringToExecute = - N'SET @SchemaExists = 0; - SET @TableExists = 0; - IF EXISTS(SELECT * FROM @@@OutputServerName@@@.@@@OutputDatabaseName@@@.INFORMATION_SCHEMA.SCHEMATA WHERE QUOTENAME(SCHEMA_NAME) = ''@@@OutputSchemaName@@@'') - SET @SchemaExists = 1 - IF EXISTS (SELECT * FROM @@@OutputServerName@@@.@@@OutputDatabaseName@@@.INFORMATION_SCHEMA.TABLES WHERE QUOTENAME(TABLE_SCHEMA) = ''@@@OutputSchemaName@@@'' AND QUOTENAME(TABLE_NAME) = ''@@@OutputTableName@@@'') - SET @TableExists = 1'; - - SET @StringToExecute = REPLACE(@StringToExecute, '@@@OutputServerName@@@', @OutputServerName) - SET @StringToExecute = REPLACE(@StringToExecute, '@@@OutputDatabaseName@@@', @OutputDatabaseName) - SET @StringToExecute = REPLACE(@StringToExecute, '@@@OutputSchemaName@@@', @OutputSchemaName) - SET @StringToExecute = REPLACE(@StringToExecute, '@@@OutputTableName@@@', @OutputTableName) - - EXEC sp_executesql @StringToExecute, N'@TableExists BIT OUTPUT, @SchemaExists BIT OUTPUT', @TableExists OUTPUT, @SchemaExists OUTPUT - - IF @SchemaExists = 1 - BEGIN - IF @TableExists = 0 - BEGIN - SET @StringToExecute = - N'CREATE TABLE @@@OutputDatabaseName@@@.@@@OutputSchemaName@@@.@@@OutputTableName@@@ - ( - [id] INT IDENTITY(1,1) NOT NULL, - [run_id] UNIQUEIDENTIFIER, - [run_datetime] DATETIME, - [server_name] NVARCHAR(128), - [database_name] NVARCHAR(128), - [schema_name] NVARCHAR(128), - [table_name] NVARCHAR(128), - [index_name] NVARCHAR(128), - [index_id] INT, - [db_schema_object_indexid] NVARCHAR(500), - [object_type] NVARCHAR(15), - [index_definition] NVARCHAR(4000), - [key_column_names_with_sort_order] NVARCHAR(MAX), - [count_key_columns] INT, - [include_column_names] NVARCHAR(MAX), - [count_included_columns] INT, - [secret_columns] NVARCHAR(MAX), - [count_secret_columns] INT, - [partition_key_column_name] NVARCHAR(MAX), - [filter_definition] NVARCHAR(MAX), - [is_indexed_view] BIT, - [is_primary_key] BIT, - [is_XML] BIT, - [is_spatial] BIT, - [is_NC_columnstore] BIT, - [is_CX_columnstore] BIT, - [is_disabled] BIT, - [is_hypothetical] BIT, - [is_padded] BIT, - [fill_factor] INT, - [is_referenced_by_foreign_key] BIT, - [last_user_seek] DATETIME, - [last_user_scan] DATETIME, - [last_user_lookup] DATETIME, - [last_user_update] DATETIME, - [total_reads] BIGINT, - [user_updates] BIGINT, - [reads_per_write] MONEY, - [index_usage_summary] NVARCHAR(200), - [partition_count] INT, - [total_rows] BIGINT, - [total_reserved_MB] NUMERIC(29,2), - [total_reserved_LOB_MB] NUMERIC(29,2), - [total_reserved_row_overflow_MB] NUMERIC(29,2), - [index_size_summary] NVARCHAR(300), - [total_row_lock_count] BIGINT, - [total_row_lock_wait_count] BIGINT, - [total_row_lock_wait_in_ms] BIGINT, - [avg_row_lock_wait_in_ms] BIGINT, - [total_page_lock_count] BIGINT, - [total_page_lock_wait_count] BIGINT, - [total_page_lock_wait_in_ms] BIGINT, - [avg_page_lock_wait_in_ms] BIGINT, - [total_index_lock_promotion_attempt_count] BIGINT, - [total_index_lock_promotion_count] BIGINT, - [data_compression_desc] VARCHAR(8000), - [create_date] DATETIME, - [modify_date] DATETIME, - [more_info] NVARCHAR(500), - [display_order] INT, - CONSTRAINT [PK_ID_@@@RunID@@@] PRIMARY KEY CLUSTERED ([id] ASC) - );' - - SET @StringToExecute = REPLACE(@StringToExecute, '@@@OutputDatabaseName@@@', @OutputDatabaseName) - SET @StringToExecute = REPLACE(@StringToExecute, '@@@OutputSchemaName@@@', @OutputSchemaName) - SET @StringToExecute = REPLACE(@StringToExecute, '@@@OutputTableName@@@', @OutputTableName) - SET @StringToExecute = REPLACE(@StringToExecute, '@@@RunID@@@', @RunID) - - IF @ValidOutputServer = 1 - BEGIN - SET @StringToExecute = REPLACE(@StringToExecute,'''','''''') - EXEC('EXEC('''+@StringToExecute+''') AT ' + @OutputServerName); - END - ELSE - BEGIN - EXEC(@StringToExecute); - END - END /* @TableExists = 0 */ - - SET @StringToExecute = - N'IF EXISTS(SELECT * FROM @@@OutputServerName@@@.@@@OutputDatabaseName@@@.INFORMATION_SCHEMA.SCHEMATA WHERE QUOTENAME(SCHEMA_NAME) = ''@@@OutputSchemaName@@@'') - AND NOT EXISTS (SELECT * FROM @@@OutputServerName@@@.@@@OutputDatabaseName@@@.INFORMATION_SCHEMA.TABLES WHERE QUOTENAME(TABLE_SCHEMA) = ''@@@OutputSchemaName@@@'' AND QUOTENAME(TABLE_NAME) = ''@@@OutputTableName@@@'') - SET @TableExists = 0 - ELSE - SET @TableExists = 1'; - - SET @TableExists = NULL - SET @StringToExecute = REPLACE(@StringToExecute, '@@@OutputServerName@@@', @OutputServerName) - SET @StringToExecute = REPLACE(@StringToExecute, '@@@OutputDatabaseName@@@', @OutputDatabaseName) - SET @StringToExecute = REPLACE(@StringToExecute, '@@@OutputSchemaName@@@', @OutputSchemaName) - SET @StringToExecute = REPLACE(@StringToExecute, '@@@OutputTableName@@@', @OutputTableName) - - EXEC sp_executesql @StringToExecute, N'@TableExists BIT OUTPUT', @TableExists OUTPUT - - IF @TableExists = 1 - BEGIN - SET @StringToExecute = - N'INSERT @@@OutputServerName@@@.@@@OutputDatabaseName@@@.@@@OutputSchemaName@@@.@@@OutputTableName@@@ - ( - [run_id], - [run_datetime], - [server_name], - [database_name], - [schema_name], - [table_name], - [index_name], - [index_id], - [db_schema_object_indexid], - [object_type], - [index_definition], - [key_column_names_with_sort_order], - [count_key_columns], - [include_column_names], - [count_included_columns], - [secret_columns], - [count_secret_columns], - [partition_key_column_name], - [filter_definition], - [is_indexed_view], - [is_primary_key], - [is_XML], - [is_spatial], - [is_NC_columnstore], - [is_CX_columnstore], - [is_disabled], - [is_hypothetical], - [is_padded], - [fill_factor], - [is_referenced_by_foreign_key], - [last_user_seek], - [last_user_scan], - [last_user_lookup], - [last_user_update], - [total_reads], - [user_updates], - [reads_per_write], - [index_usage_summary], - [partition_count], - [total_rows], - [total_reserved_MB], - [total_reserved_LOB_MB], - [total_reserved_row_overflow_MB], - [index_size_summary], - [total_row_lock_count], - [total_row_lock_wait_count], - [total_row_lock_wait_in_ms], - [avg_row_lock_wait_in_ms], - [total_page_lock_count], - [total_page_lock_wait_count], - [total_page_lock_wait_in_ms], - [avg_page_lock_wait_in_ms], - [total_index_lock_promotion_attempt_count], - [total_index_lock_promotion_count], - [data_compression_desc], - [create_date], - [modify_date], - [more_info], - [display_order] - ) - SELECT ''@@@RunID@@@'', - ''@@@GETDATE@@@'', - ''@@@LocalServerName@@@'', - -- Below should be a copy/paste of the real query - -- Make sure all quotes are escaped - i.[database_name] AS [Database Name], - i.[schema_name] AS [Schema Name], - i.[object_name] AS [Object Name], - ISNULL(i.index_name, '''') AS [Index Name], - CAST(i.index_id AS VARCHAR(10))AS [Index ID], - db_schema_object_indexid AS [Details: schema.table.index(indexid)], - CASE WHEN index_id IN ( 1, 0 ) THEN ''TABLE'' - ELSE ''NonClustered'' - END AS [Object Type], - index_definition AS [Definition: [Property]] ColumnName {datatype maxbytes}], - ISNULL(LTRIM(key_column_names_with_sort_order), '''') AS [Key Column Names With Sort], - ISNULL(count_key_columns, 0) AS [Count Key Columns], - ISNULL(include_column_names, '''') AS [Include Column Names], - ISNULL(count_included_columns,0) AS [Count Included Columns], - ISNULL(secret_columns,'''') AS [Secret Column Names], - ISNULL(count_secret_columns,0) AS [Count Secret Columns], - ISNULL(partition_key_column_name, '''') AS [Partition Key Column Name], - ISNULL(filter_definition, '''') AS [Filter Definition], - is_indexed_view AS [Is Indexed View], - is_primary_key AS [Is Primary Key], - is_XML AS [Is XML], - is_spatial AS [Is Spatial], - is_NC_columnstore AS [Is NC Columnstore], - is_CX_columnstore AS [Is CX Columnstore], - is_disabled AS [Is Disabled], - is_hypothetical AS [Is Hypothetical], - is_padded AS [Is Padded], - fill_factor AS [Fill Factor], - is_referenced_by_foreign_key AS [Is Reference by Foreign Key], - last_user_seek AS [Last User Seek], - last_user_scan AS [Last User Scan], - last_user_lookup AS [Last User Lookup], - last_user_update AS [Last User Update], - total_reads AS [Total Reads], - user_updates AS [User Updates], - reads_per_write AS [Reads Per Write], - index_usage_summary AS [Index Usage], - sz.partition_count AS [Partition Count], - sz.total_rows AS [Rows], - sz.total_reserved_MB AS [Reserved MB], - sz.total_reserved_LOB_MB AS [Reserved LOB MB], - sz.total_reserved_row_overflow_MB AS [Reserved Row Overflow MB], - sz.index_size_summary AS [Index Size], - sz.total_row_lock_count AS [Row Lock Count], - sz.total_row_lock_wait_count AS [Row Lock Wait Count], - sz.total_row_lock_wait_in_ms AS [Row Lock Wait ms], - sz.avg_row_lock_wait_in_ms AS [Avg Row Lock Wait ms], - sz.total_page_lock_count AS [Page Lock Count], - sz.total_page_lock_wait_count AS [Page Lock Wait Count], - sz.total_page_lock_wait_in_ms AS [Page Lock Wait ms], - sz.avg_page_lock_wait_in_ms AS [Avg Page Lock Wait ms], - sz.total_index_lock_promotion_attempt_count AS [Lock Escalation Attempts], - sz.total_index_lock_promotion_count AS [Lock Escalations], - sz.data_compression_desc AS [Data Compression], - i.create_date AS [Create Date], - i.modify_date AS [Modify Date], - more_info AS [More Info], - 1 AS [Display Order] - FROM #IndexSanity AS i - LEFT JOIN #IndexSanitySize AS sz ON i.index_sanity_id = sz.index_sanity_id - ORDER BY [Database Name], [Schema Name], [Object Name], [Index ID] - OPTION (RECOMPILE);'; - - SET @StringToExecute = REPLACE(@StringToExecute, '@@@OutputServerName@@@', @OutputServerName) - SET @StringToExecute = REPLACE(@StringToExecute, '@@@OutputDatabaseName@@@', @OutputDatabaseName) - SET @StringToExecute = REPLACE(@StringToExecute, '@@@OutputSchemaName@@@', @OutputSchemaName) - SET @StringToExecute = REPLACE(@StringToExecute, '@@@OutputTableName@@@', @OutputTableName) - SET @StringToExecute = REPLACE(@StringToExecute, '@@@RunID@@@', @RunID) - SET @StringToExecute = REPLACE(@StringToExecute, '@@@GETDATE@@@', GETDATE()) - SET @StringToExecute = REPLACE(@StringToExecute, '@@@LocalServerName@@@', CAST(SERVERPROPERTY('ServerName') AS NVARCHAR(128))) - EXEC(@StringToExecute); - END /* @TableExists = 1 */ - ELSE - RAISERROR('Creation of the output table failed.', 16, 0) - END /* @TableExists = 0 */ - ELSE - RAISERROR (N'Invalid schema name, data could not be saved.', 16, 0) - END /* @ValidOutputLocation = 1 */ - ELSE - - - SELECT i.[database_name] AS [Database Name], - i.[schema_name] AS [Schema Name], - i.[object_name] AS [Object Name], - ISNULL(i.index_name, '') AS [Index Name], - CAST(i.index_id AS VARCHAR(10))AS [Index ID], - db_schema_object_indexid AS [Details: schema.table.index(indexid)], - CASE WHEN index_id IN ( 1, 0 ) THEN 'TABLE' - ELSE 'NonClustered' - END AS [Object Type], - index_definition AS [Definition: [Property]] ColumnName {datatype maxbytes}], - ISNULL(LTRIM(key_column_names_with_sort_order), '') AS [Key Column Names With Sort], - ISNULL(count_key_columns, 0) AS [Count Key Columns], - ISNULL(include_column_names, '') AS [Include Column Names], - ISNULL(count_included_columns,0) AS [Count Included Columns], - ISNULL(secret_columns,'') AS [Secret Column Names], - ISNULL(count_secret_columns,0) AS [Count Secret Columns], - ISNULL(partition_key_column_name, '') AS [Partition Key Column Name], - ISNULL(filter_definition, '') AS [Filter Definition], - is_indexed_view AS [Is Indexed View], - is_primary_key AS [Is Primary Key], - is_XML AS [Is XML], - is_spatial AS [Is Spatial], - is_NC_columnstore AS [Is NC Columnstore], - is_CX_columnstore AS [Is CX Columnstore], - is_disabled AS [Is Disabled], - is_hypothetical AS [Is Hypothetical], - is_padded AS [Is Padded], - fill_factor AS [Fill Factor], - is_referenced_by_foreign_key AS [Is Reference by Foreign Key], - last_user_seek AS [Last User Seek], - last_user_scan AS [Last User Scan], - last_user_lookup AS [Last User Lookup], - last_user_update AS [Last User Update], - total_reads AS [Total Reads], - user_updates AS [User Updates], - reads_per_write AS [Reads Per Write], - index_usage_summary AS [Index Usage], - sz.partition_count AS [Partition Count], - sz.total_rows AS [Rows], - sz.total_reserved_MB AS [Reserved MB], - sz.total_reserved_LOB_MB AS [Reserved LOB MB], - sz.total_reserved_row_overflow_MB AS [Reserved Row Overflow MB], - sz.index_size_summary AS [Index Size], - sz.total_row_lock_count AS [Row Lock Count], - sz.total_row_lock_wait_count AS [Row Lock Wait Count], - sz.total_row_lock_wait_in_ms AS [Row Lock Wait ms], - sz.avg_row_lock_wait_in_ms AS [Avg Row Lock Wait ms], - sz.total_page_lock_count AS [Page Lock Count], - sz.total_page_lock_wait_count AS [Page Lock Wait Count], - sz.total_page_lock_wait_in_ms AS [Page Lock Wait ms], - sz.avg_page_lock_wait_in_ms AS [Avg Page Lock Wait ms], - sz.total_index_lock_promotion_attempt_count AS [Lock Escalation Attempts], - sz.total_index_lock_promotion_count AS [Lock Escalations], - sz.data_compression_desc AS [Data Compression], - i.create_date AS [Create Date], - i.modify_date AS [Modify Date], - more_info AS [More Info], - 1 AS [Display Order] - FROM #IndexSanity AS i --left join here so we don't lose disabled nc indexes - LEFT JOIN #IndexSanitySize AS sz ON i.index_sanity_id = sz.index_sanity_id - ORDER BY [Database Name], [Schema Name], [Object Name], [Index ID] - OPTION (RECOMPILE); - - - - END /* End @Mode=2 (index detail)*/ - ELSE IF @Mode=3 /*Missing index Detail*/ - BEGIN - - WITH create_date AS ( - SELECT i.database_id, - i.schema_name, - i.[object_id], - ISNULL(NULLIF(MAX(DATEDIFF(DAY, i.create_date, SYSDATETIME())), 0), 1) AS create_days - FROM #IndexSanity AS i - GROUP BY i.database_id, i.schema_name, i.object_id - ) - SELECT - mi.database_name AS [Database Name], - mi.[schema_name] AS [Schema], - mi.table_name AS [Table], - CAST((mi.magic_benefit_number / CASE WHEN cd.create_days < @DaysUptime THEN cd.create_days ELSE @DaysUptime END) AS BIGINT) - AS [Magic Benefit Number], - mi.missing_index_details AS [Missing Index Details], - mi.avg_total_user_cost AS [Avg Query Cost], - mi.avg_user_impact AS [Est Index Improvement], - mi.user_seeks AS [Seeks], - mi.user_scans AS [Scans], - mi.unique_compiles AS [Compiles], - mi.equality_columns AS [Equality Columns], - mi.inequality_columns AS [Inequality Columns], - mi.included_columns AS [Included Columns], - mi.index_estimated_impact AS [Estimated Impact], - mi.create_tsql AS [Create TSQL], - mi.more_info AS [More Info], - 1 AS [Display Order], - mi.is_low - FROM #MissingIndexes AS mi - LEFT JOIN create_date AS cd - ON mi.[object_id] = cd.object_id - AND mi.database_id = cd.database_id - AND mi.schema_name = cd.schema_name - /* Minimum benefit threshold = 100k/day of uptime OR since table creation date, whichever is lower*/ - WHERE (mi.magic_benefit_number / CASE WHEN cd.create_days < @DaysUptime THEN cd.create_days ELSE @DaysUptime END) >= 100000 - UNION ALL - SELECT - @ScriptVersionName, - N'From Your Community Volunteers' , - N'http://FirstResponderKit.org' , - 100000000000, - N'', - NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL, - NULL, 0 AS [Display Order], NULL AS is_low - ORDER BY [Display Order] ASC, is_low, [Magic Benefit Number] DESC - OPTION (RECOMPILE); - - END /* End @Mode=3 (index detail)*/ -END -END TRY - -BEGIN CATCH - RAISERROR (N'Failure analyzing temp tables.', 0,1) WITH NOWAIT; - - SELECT @msg = ERROR_MESSAGE(), @ErrorSeverity = ERROR_SEVERITY(), @ErrorState = ERROR_STATE(); - - RAISERROR (@msg, - @ErrorSeverity, - @ErrorState - ); - - WHILE @@trancount > 0 - ROLLBACK; - - RETURN; - END CATCH; -GO diff --git a/QueryTemplates/Performance/who_is_active_v11_17.sql b/QueryTemplates/Performance/who_is_active_v11_17.sql deleted file mode 100644 index 9a35bc8..0000000 --- a/QueryTemplates/Performance/who_is_active_v11_17.sql +++ /dev/null @@ -1,5170 +0,0 @@ -USE master -GO - -IF NOT EXISTS (SELECT * FROM INFORMATION_SCHEMA.ROUTINES WHERE ROUTINE_NAME = 'sp_WhoIsActive') - EXEC ('CREATE PROC dbo.sp_WhoIsActive AS SELECT ''stub version, to be replaced''') -GO - -/********************************************************************************************* -Who Is Active? v11.17 (2016-10-18) -(C) 2007-2016, Adam Machanic - -Feedback: mailto:amachanic@gmail.com -Updates: http://whoisactive.com - -License: - Who is Active? is free to download and use for personal, educational, and internal - corporate purposes, provided that this header is preserved. Redistribution or sale - of Who is Active?, in whole or in part, is prohibited without the author's express - written consent. -*********************************************************************************************/ -ALTER PROC dbo.sp_WhoIsActive -( ---~ - --Filters--Both inclusive and exclusive - --Set either filter to '' to disable - --Valid filter types are: session, program, database, login, and host - --Session is a session ID, and either 0 or '' can be used to indicate "all" sessions - --All other filter types support % or _ as wildcards - @filter sysname = '', - @filter_type VARCHAR(10) = 'session', - @not_filter sysname = '', - @not_filter_type VARCHAR(10) = 'session', - - --Retrieve data about the calling session? - @show_own_spid BIT = 0, - - --Retrieve data about system sessions? - @show_system_spids BIT = 0, - - --Controls how sleeping SPIDs are handled, based on the idea of levels of interest - --0 does not pull any sleeping SPIDs - --1 pulls only those sleeping SPIDs that also have an open transaction - --2 pulls all sleeping SPIDs - @show_sleeping_spids TINYINT = 1, - - --If 1, gets the full stored procedure or running batch, when available - --If 0, gets only the actual statement that is currently running in the batch or procedure - @get_full_inner_text BIT = 0, - - --Get associated query plans for running tasks, if available - --If @get_plans = 1, gets the plan based on the request's statement offset - --If @get_plans = 2, gets the entire plan based on the request's plan_handle - @get_plans TINYINT = 0, - - --Get the associated outer ad hoc query or stored procedure call, if available - @get_outer_command BIT = 0, - - --Enables pulling transaction log write info and transaction duration - @get_transaction_info BIT = 0, - - --Get information on active tasks, based on three interest levels - --Level 0 does not pull any task-related information - --Level 1 is a lightweight mode that pulls the top non-CXPACKET wait, giving preference to blockers - --Level 2 pulls all available task-based metrics, including: - --number of active tasks, current wait stats, physical I/O, context switches, and blocker information - @get_task_info TINYINT = 1, - - --Gets associated locks for each request, aggregated in an XML format - @get_locks BIT = 0, - - --Get average time for past runs of an active query - --(based on the combination of plan handle, sql handle, and offset) - @get_avg_time BIT = 0, - - --Get additional non-performance-related information about the session or request - --text_size, language, date_format, date_first, quoted_identifier, arithabort, ansi_null_dflt_on, - --ansi_defaults, ansi_warnings, ansi_padding, ansi_nulls, concat_null_yields_null, - --transaction_isolation_level, lock_timeout, deadlock_priority, row_count, command_type - -- - --If a SQL Agent job is running, an subnode called agent_info will be populated with some or all of - --the following: job_id, job_name, step_id, step_name, msdb_query_error (in the event of an error) - -- - --If @get_task_info is set to 2 and a lock wait is detected, a subnode called block_info will be - --populated with some or all of the following: lock_type, database_name, object_id, file_id, hobt_id, - --applock_hash, metadata_resource, metadata_class_id, object_name, schema_name - @get_additional_info BIT = 0, - - --Walk the blocking chain and count the number of - --total SPIDs blocked all the way down by a given session - --Also enables task_info Level 1, if @get_task_info is set to 0 - @find_block_leaders BIT = 0, - - --Pull deltas on various metrics - --Interval in seconds to wait before doing the second data pull - @delta_interval TINYINT = 0, - - --List of desired output columns, in desired order - --Note that the final output will be the intersection of all enabled features and all - --columns in the list. Therefore, only columns associated with enabled features will - --actually appear in the output. Likewise, removing columns from this list may effectively - --disable features, even if they are turned on - -- - --Each element in this list must be one of the valid output column names. Names must be - --delimited by square brackets. White space, formatting, and additional characters are - --allowed, as long as the list contains exact matches of delimited valid column names. - @output_column_list VARCHAR(8000) = '[dd%][session_id][sql_text][sql_command][login_name][wait_info][tasks][tran_log%][cpu%][temp%][block%][reads%][writes%][context%][physical%][query_plan][locks][%]', - - --Column(s) by which to sort output, optionally with sort directions. - --Valid column choices: - --session_id, physical_io, reads, physical_reads, writes, tempdb_allocations, - --tempdb_current, CPU, context_switches, used_memory, physical_io_delta, - --reads_delta, physical_reads_delta, writes_delta, tempdb_allocations_delta, - --tempdb_current_delta, CPU_delta, context_switches_delta, used_memory_delta, - --tasks, tran_start_time, open_tran_count, blocking_session_id, blocked_session_count, - --percent_complete, host_name, login_name, database_name, start_time, login_time - -- - --Note that column names in the list must be bracket-delimited. Commas and/or white - --space are not required. - @sort_order VARCHAR(500) = '[start_time] ASC', - - --Formats some of the output columns in a more "human readable" form - --0 disables outfput format - --1 formats the output for variable-width fonts - --2 formats the output for fixed-width fonts - @format_output TINYINT = 1, - - --If set to a non-blank value, the script will attempt to insert into the specified - --destination table. Please note that the script will not verify that the table exists, - --or that it has the correct schema, before doing the insert. - --Table can be specified in one, two, or three-part format - @destination_table VARCHAR(4000) = '', - - --If set to 1, no data collection will happen and no result set will be returned; instead, - --a CREATE TABLE statement will be returned via the @schema parameter, which will match - --the schema of the result set that would be returned by using the same collection of the - --rest of the parameters. The CREATE TABLE statement will have a placeholder token of - -- in place of an actual table name. - @return_schema BIT = 0, - @schema VARCHAR(MAX) = NULL OUTPUT, - - --Help! What do I do? - @help BIT = 0 ---~ -) -/* -OUTPUT COLUMNS --------------- -Formatted/Non: [session_id] [smallint] NOT NULL - Session ID (a.k.a. SPID) - -Formatted: [dd hh:mm:ss.mss] [varchar](15) NULL -Non-Formatted: - For an active request, time the query has been running - For a sleeping session, time since the last batch completed - -Formatted: [dd hh:mm:ss.mss (avg)] [varchar](15) NULL -Non-Formatted: [avg_elapsed_time] [int] NULL - (Requires @get_avg_time option) - How much time has the active portion of the query taken in the past, on average? - -Formatted: [physical_io] [varchar](30) NULL -Non-Formatted: [physical_io] [bigint] NULL - Shows the number of physical I/Os, for active requests - -Formatted: [reads] [varchar](30) NULL -Non-Formatted: [reads] [bigint] NULL - For an active request, number of reads done for the current query - For a sleeping session, total number of reads done over the lifetime of the session - -Formatted: [physical_reads] [varchar](30) NULL -Non-Formatted: [physical_reads] [bigint] NULL - For an active request, number of physical reads done for the current query - For a sleeping session, total number of physical reads done over the lifetime of the session - -Formatted: [writes] [varchar](30) NULL -Non-Formatted: [writes] [bigint] NULL - For an active request, number of writes done for the current query - For a sleeping session, total number of writes done over the lifetime of the session - -Formatted: [tempdb_allocations] [varchar](30) NULL -Non-Formatted: [tempdb_allocations] [bigint] NULL - For an active request, number of TempDB writes done for the current query - For a sleeping session, total number of TempDB writes done over the lifetime of the session - -Formatted: [tempdb_current] [varchar](30) NULL -Non-Formatted: [tempdb_current] [bigint] NULL - For an active request, number of TempDB pages currently allocated for the query - For a sleeping session, number of TempDB pages currently allocated for the session - -Formatted: [CPU] [varchar](30) NULL -Non-Formatted: [CPU] [int] NULL - For an active request, total CPU time consumed by the current query - For a sleeping session, total CPU time consumed over the lifetime of the session - -Formatted: [context_switches] [varchar](30) NULL -Non-Formatted: [context_switches] [bigint] NULL - Shows the number of context switches, for active requests - -Formatted: [used_memory] [varchar](30) NOT NULL -Non-Formatted: [used_memory] [bigint] NOT NULL - For an active request, total memory consumption for the current query - For a sleeping session, total current memory consumption - -Formatted: [physical_io_delta] [varchar](30) NULL -Non-Formatted: [physical_io_delta] [bigint] NULL - (Requires @delta_interval option) - Difference between the number of physical I/Os reported on the first and second collections. - If the request started after the first collection, the value will be NULL - -Formatted: [reads_delta] [varchar](30) NULL -Non-Formatted: [reads_delta] [bigint] NULL - (Requires @delta_interval option) - Difference between the number of reads reported on the first and second collections. - If the request started after the first collection, the value will be NULL - -Formatted: [physical_reads_delta] [varchar](30) NULL -Non-Formatted: [physical_reads_delta] [bigint] NULL - (Requires @delta_interval option) - Difference between the number of physical reads reported on the first and second collections. - If the request started after the first collection, the value will be NULL - -Formatted: [writes_delta] [varchar](30) NULL -Non-Formatted: [writes_delta] [bigint] NULL - (Requires @delta_interval option) - Difference between the number of writes reported on the first and second collections. - If the request started after the first collection, the value will be NULL - -Formatted: [tempdb_allocations_delta] [varchar](30) NULL -Non-Formatted: [tempdb_allocations_delta] [bigint] NULL - (Requires @delta_interval option) - Difference between the number of TempDB writes reported on the first and second collections. - If the request started after the first collection, the value will be NULL - -Formatted: [tempdb_current_delta] [varchar](30) NULL -Non-Formatted: [tempdb_current_delta] [bigint] NULL - (Requires @delta_interval option) - Difference between the number of allocated TempDB pages reported on the first and second - collections. If the request started after the first collection, the value will be NULL - -Formatted: [CPU_delta] [varchar](30) NULL -Non-Formatted: [CPU_delta] [int] NULL - (Requires @delta_interval option) - Difference between the CPU time reported on the first and second collections. - If the request started after the first collection, the value will be NULL - -Formatted: [context_switches_delta] [varchar](30) NULL -Non-Formatted: [context_switches_delta] [bigint] NULL - (Requires @delta_interval option) - Difference between the context switches count reported on the first and second collections - If the request started after the first collection, the value will be NULL - -Formatted: [used_memory_delta] [varchar](30) NULL -Non-Formatted: [used_memory_delta] [bigint] NULL - Difference between the memory usage reported on the first and second collections - If the request started after the first collection, the value will be NULL - -Formatted: [tasks] [varchar](30) NULL -Non-Formatted: [tasks] [smallint] NULL - Number of worker tasks currently allocated, for active requests - -Formatted/Non: [status] [varchar](30) NOT NULL - Activity status for the session (running, sleeping, etc) - -Formatted/Non: [wait_info] [nvarchar](4000) NULL - Aggregates wait information, in the following format: - (Ax: Bms/Cms/Dms)E - A is the number of waiting tasks currently waiting on resource type E. B/C/D are wait - times, in milliseconds. If only one thread is waiting, its wait time will be shown as B. - If two tasks are waiting, each of their wait times will be shown (B/C). If three or more - tasks are waiting, the minimum, average, and maximum wait times will be shown (B/C/D). - If wait type E is a page latch wait and the page is of a "special" type (e.g. PFS, GAM, SGAM), - the page type will be identified. - If wait type E is CXPACKET, the nodeId from the query plan will be identified - -Formatted/Non: [locks] [xml] NULL - (Requires @get_locks option) - Aggregates lock information, in XML format. - The lock XML includes the lock mode, locked object, and aggregates the number of requests. - Attempts are made to identify locked objects by name - -Formatted/Non: [tran_start_time] [datetime] NULL - (Requires @get_transaction_info option) - Date and time that the first transaction opened by a session caused a transaction log - write to occur. - -Formatted/Non: [tran_log_writes] [nvarchar](4000) NULL - (Requires @get_transaction_info option) - Aggregates transaction log write information, in the following format: - A:wB (C kB) - A is a database that has been touched by an active transaction - B is the number of log writes that have been made in the database as a result of the transaction - C is the number of log kilobytes consumed by the log records - -Formatted: [open_tran_count] [varchar](30) NULL -Non-Formatted: [open_tran_count] [smallint] NULL - Shows the number of open transactions the session has open - -Formatted: [sql_command] [xml] NULL -Non-Formatted: [sql_command] [nvarchar](max) NULL - (Requires @get_outer_command option) - Shows the "outer" SQL command, i.e. the text of the batch or RPC sent to the server, - if available - -Formatted: [sql_text] [xml] NULL -Non-Formatted: [sql_text] [nvarchar](max) NULL - Shows the SQL text for active requests or the last statement executed - for sleeping sessions, if available in either case. - If @get_full_inner_text option is set, shows the full text of the batch. - Otherwise, shows only the active statement within the batch. - If the query text is locked, a special timeout message will be sent, in the following format: - - If an error occurs, an error message will be sent, in the following format: - - -Formatted/Non: [query_plan] [xml] NULL - (Requires @get_plans option) - Shows the query plan for the request, if available. - If the plan is locked, a special timeout message will be sent, in the following format: - - If an error occurs, an error message will be sent, in the following format: - - -Formatted/Non: [blocking_session_id] [smallint] NULL - When applicable, shows the blocking SPID - -Formatted: [blocked_session_count] [varchar](30) NULL -Non-Formatted: [blocked_session_count] [smallint] NULL - (Requires @find_block_leaders option) - The total number of SPIDs blocked by this session, - all the way down the blocking chain. - -Formatted: [percent_complete] [varchar](30) NULL -Non-Formatted: [percent_complete] [real] NULL - When applicable, shows the percent complete (e.g. for backups, restores, and some rollbacks) - -Formatted/Non: [host_name] [sysname] NOT NULL - Shows the host name for the connection - -Formatted/Non: [login_name] [sysname] NOT NULL - Shows the login name for the connection - -Formatted/Non: [database_name] [sysname] NULL - Shows the connected database - -Formatted/Non: [program_name] [sysname] NULL - Shows the reported program/application name - -Formatted/Non: [additional_info] [xml] NULL - (Requires @get_additional_info option) - Returns additional non-performance-related session/request information - If the script finds a SQL Agent job running, the name of the job and job step will be reported - If @get_task_info = 2 and the script finds a lock wait, the locked object will be reported - -Formatted/Non: [start_time] [datetime] NOT NULL - For active requests, shows the time the request started - For sleeping sessions, shows the time the last batch completed - -Formatted/Non: [login_time] [datetime] NOT NULL - Shows the time that the session connected - -Formatted/Non: [request_id] [int] NULL - For active requests, shows the request_id - Should be 0 unless MARS is being used - -Formatted/Non: [collection_time] [datetime] NOT NULL - Time that this script's final SELECT ran -*/ -AS -BEGIN; - SET NOCOUNT ON; - SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED; - SET QUOTED_IDENTIFIER ON; - SET ANSI_PADDING ON; - SET CONCAT_NULL_YIELDS_NULL ON; - SET ANSI_WARNINGS ON; - SET NUMERIC_ROUNDABORT OFF; - SET ARITHABORT ON; - - IF - @filter IS NULL - OR @filter_type IS NULL - OR @not_filter IS NULL - OR @not_filter_type IS NULL - OR @show_own_spid IS NULL - OR @show_system_spids IS NULL - OR @show_sleeping_spids IS NULL - OR @get_full_inner_text IS NULL - OR @get_plans IS NULL - OR @get_outer_command IS NULL - OR @get_transaction_info IS NULL - OR @get_task_info IS NULL - OR @get_locks IS NULL - OR @get_avg_time IS NULL - OR @get_additional_info IS NULL - OR @find_block_leaders IS NULL - OR @delta_interval IS NULL - OR @format_output IS NULL - OR @output_column_list IS NULL - OR @sort_order IS NULL - OR @return_schema IS NULL - OR @destination_table IS NULL - OR @help IS NULL - BEGIN; - RAISERROR('Input parameters cannot be NULL', 16, 1); - RETURN; - END; - - IF @filter_type NOT IN ('session', 'program', 'database', 'login', 'host') - BEGIN; - RAISERROR('Valid filter types are: session, program, database, login, host', 16, 1); - RETURN; - END; - - IF @filter_type = 'session' AND @filter LIKE '%[^0123456789]%' - BEGIN; - RAISERROR('Session filters must be valid integers', 16, 1); - RETURN; - END; - - IF @not_filter_type NOT IN ('session', 'program', 'database', 'login', 'host') - BEGIN; - RAISERROR('Valid filter types are: session, program, database, login, host', 16, 1); - RETURN; - END; - - IF @not_filter_type = 'session' AND @not_filter LIKE '%[^0123456789]%' - BEGIN; - RAISERROR('Session filters must be valid integers', 16, 1); - RETURN; - END; - - IF @show_sleeping_spids NOT IN (0, 1, 2) - BEGIN; - RAISERROR('Valid values for @show_sleeping_spids are: 0, 1, or 2', 16, 1); - RETURN; - END; - - IF @get_plans NOT IN (0, 1, 2) - BEGIN; - RAISERROR('Valid values for @get_plans are: 0, 1, or 2', 16, 1); - RETURN; - END; - - IF @get_task_info NOT IN (0, 1, 2) - BEGIN; - RAISERROR('Valid values for @get_task_info are: 0, 1, or 2', 16, 1); - RETURN; - END; - - IF @format_output NOT IN (0, 1, 2) - BEGIN; - RAISERROR('Valid values for @format_output are: 0, 1, or 2', 16, 1); - RETURN; - END; - - IF @help = 1 - BEGIN; - DECLARE - @header VARCHAR(MAX), - @params VARCHAR(MAX), - @outputs VARCHAR(MAX); - - SELECT - @header = - REPLACE - ( - REPLACE - ( - CONVERT - ( - VARCHAR(MAX), - SUBSTRING - ( - t.text, - CHARINDEX('/' + REPLICATE('*', 93), t.text) + 94, - CHARINDEX(REPLICATE('*', 93) + '/', t.text) - (CHARINDEX('/' + REPLICATE('*', 93), t.text) + 94) - ) - ), - CHAR(13)+CHAR(10), - CHAR(13) - ), - ' ', - '' - ), - @params = - CHAR(13) + - REPLACE - ( - REPLACE - ( - CONVERT - ( - VARCHAR(MAX), - SUBSTRING - ( - t.text, - CHARINDEX('--~', t.text) + 5, - CHARINDEX('--~', t.text, CHARINDEX('--~', t.text) + 5) - (CHARINDEX('--~', t.text) + 5) - ) - ), - CHAR(13)+CHAR(10), - CHAR(13) - ), - ' ', - '' - ), - @outputs = - CHAR(13) + - REPLACE - ( - REPLACE - ( - REPLACE - ( - CONVERT - ( - VARCHAR(MAX), - SUBSTRING - ( - t.text, - CHARINDEX('OUTPUT COLUMNS'+CHAR(13)+CHAR(10)+'--------------', t.text) + 32, - CHARINDEX('*/', t.text, CHARINDEX('OUTPUT COLUMNS'+CHAR(13)+CHAR(10)+'--------------', t.text) + 32) - (CHARINDEX('OUTPUT COLUMNS'+CHAR(13)+CHAR(10)+'--------------', t.text) + 32) - ) - ), - CHAR(9), - CHAR(255) - ), - CHAR(13)+CHAR(10), - CHAR(13) - ), - ' ', - '' - ) + - CHAR(13) - FROM sys.dm_exec_requests AS r - CROSS APPLY sys.dm_exec_sql_text(r.sql_handle) AS t - WHERE - r.session_id = @@SPID; - - WITH - a0 AS - (SELECT 1 AS n UNION ALL SELECT 1), - a1 AS - (SELECT 1 AS n FROM a0 AS a, a0 AS b), - a2 AS - (SELECT 1 AS n FROM a1 AS a, a1 AS b), - a3 AS - (SELECT 1 AS n FROM a2 AS a, a2 AS b), - a4 AS - (SELECT 1 AS n FROM a3 AS a, a3 AS b), - numbers AS - ( - SELECT TOP(LEN(@header) - 1) - ROW_NUMBER() OVER - ( - ORDER BY (SELECT NULL) - ) AS number - FROM a4 - ORDER BY - number - ) - SELECT - RTRIM(LTRIM( - SUBSTRING - ( - @header, - number + 1, - CHARINDEX(CHAR(13), @header, number + 1) - number - 1 - ) - )) AS [------header---------------------------------------------------------------------------------------------------------------] - FROM numbers - WHERE - SUBSTRING(@header, number, 1) = CHAR(13); - - WITH - a0 AS - (SELECT 1 AS n UNION ALL SELECT 1), - a1 AS - (SELECT 1 AS n FROM a0 AS a, a0 AS b), - a2 AS - (SELECT 1 AS n FROM a1 AS a, a1 AS b), - a3 AS - (SELECT 1 AS n FROM a2 AS a, a2 AS b), - a4 AS - (SELECT 1 AS n FROM a3 AS a, a3 AS b), - numbers AS - ( - SELECT TOP(LEN(@params) - 1) - ROW_NUMBER() OVER - ( - ORDER BY (SELECT NULL) - ) AS number - FROM a4 - ORDER BY - number - ), - tokens AS - ( - SELECT - RTRIM(LTRIM( - SUBSTRING - ( - @params, - number + 1, - CHARINDEX(CHAR(13), @params, number + 1) - number - 1 - ) - )) AS token, - number, - CASE - WHEN SUBSTRING(@params, number + 1, 1) = CHAR(13) THEN number - ELSE COALESCE(NULLIF(CHARINDEX(',' + CHAR(13) + CHAR(13), @params, number), 0), LEN(@params)) - END AS param_group, - ROW_NUMBER() OVER - ( - PARTITION BY - CHARINDEX(',' + CHAR(13) + CHAR(13), @params, number), - SUBSTRING(@params, number+1, 1) - ORDER BY - number - ) AS group_order - FROM numbers - WHERE - SUBSTRING(@params, number, 1) = CHAR(13) - ), - parsed_tokens AS - ( - SELECT - MIN - ( - CASE - WHEN token LIKE '@%' THEN token - ELSE NULL - END - ) AS parameter, - MIN - ( - CASE - WHEN token LIKE '--%' THEN RIGHT(token, LEN(token) - 2) - ELSE NULL - END - ) AS description, - param_group, - group_order - FROM tokens - WHERE - NOT - ( - token = '' - AND group_order > 1 - ) - GROUP BY - param_group, - group_order - ) - SELECT - CASE - WHEN description IS NULL AND parameter IS NULL THEN '-------------------------------------------------------------------------' - WHEN param_group = MAX(param_group) OVER() THEN parameter - ELSE COALESCE(LEFT(parameter, LEN(parameter) - 1), '') - END AS [------parameter----------------------------------------------------------], - CASE - WHEN description IS NULL AND parameter IS NULL THEN '----------------------------------------------------------------------------------------------------------------------' - ELSE COALESCE(description, '') - END AS [------description-----------------------------------------------------------------------------------------------------] - FROM parsed_tokens - ORDER BY - param_group, - group_order; - - WITH - a0 AS - (SELECT 1 AS n UNION ALL SELECT 1), - a1 AS - (SELECT 1 AS n FROM a0 AS a, a0 AS b), - a2 AS - (SELECT 1 AS n FROM a1 AS a, a1 AS b), - a3 AS - (SELECT 1 AS n FROM a2 AS a, a2 AS b), - a4 AS - (SELECT 1 AS n FROM a3 AS a, a3 AS b), - numbers AS - ( - SELECT TOP(LEN(@outputs) - 1) - ROW_NUMBER() OVER - ( - ORDER BY (SELECT NULL) - ) AS number - FROM a4 - ORDER BY - number - ), - tokens AS - ( - SELECT - RTRIM(LTRIM( - SUBSTRING - ( - @outputs, - number + 1, - CASE - WHEN - COALESCE(NULLIF(CHARINDEX(CHAR(13) + 'Formatted', @outputs, number + 1), 0), LEN(@outputs)) < - COALESCE(NULLIF(CHARINDEX(CHAR(13) + CHAR(255) COLLATE Latin1_General_Bin2, @outputs, number + 1), 0), LEN(@outputs)) - THEN COALESCE(NULLIF(CHARINDEX(CHAR(13) + 'Formatted', @outputs, number + 1), 0), LEN(@outputs)) - number - 1 - ELSE - COALESCE(NULLIF(CHARINDEX(CHAR(13) + CHAR(255) COLLATE Latin1_General_Bin2, @outputs, number + 1), 0), LEN(@outputs)) - number - 1 - END - ) - )) AS token, - number, - COALESCE(NULLIF(CHARINDEX(CHAR(13) + 'Formatted', @outputs, number + 1), 0), LEN(@outputs)) AS output_group, - ROW_NUMBER() OVER - ( - PARTITION BY - COALESCE(NULLIF(CHARINDEX(CHAR(13) + 'Formatted', @outputs, number + 1), 0), LEN(@outputs)) - ORDER BY - number - ) AS output_group_order - FROM numbers - WHERE - SUBSTRING(@outputs, number, 10) = CHAR(13) + 'Formatted' - OR SUBSTRING(@outputs, number, 2) = CHAR(13) + CHAR(255) COLLATE Latin1_General_Bin2 - ), - output_tokens AS - ( - SELECT - *, - CASE output_group_order - WHEN 2 THEN MAX(CASE output_group_order WHEN 1 THEN token ELSE NULL END) OVER (PARTITION BY output_group) - ELSE '' - END COLLATE Latin1_General_Bin2 AS column_info - FROM tokens - ) - SELECT - CASE output_group_order - WHEN 1 THEN '-----------------------------------' - WHEN 2 THEN - CASE - WHEN CHARINDEX('Formatted/Non:', column_info) = 1 THEN - SUBSTRING(column_info, CHARINDEX(CHAR(255) COLLATE Latin1_General_Bin2, column_info)+1, CHARINDEX(']', column_info, CHARINDEX(CHAR(255) COLLATE Latin1_General_Bin2, column_info)+2) - CHARINDEX(CHAR(255) COLLATE Latin1_General_Bin2, column_info)) - ELSE - SUBSTRING(column_info, CHARINDEX(CHAR(255) COLLATE Latin1_General_Bin2, column_info)+2, CHARINDEX(']', column_info, CHARINDEX(CHAR(255) COLLATE Latin1_General_Bin2, column_info)+2) - CHARINDEX(CHAR(255) COLLATE Latin1_General_Bin2, column_info)-1) - END - ELSE '' - END AS formatted_column_name, - CASE output_group_order - WHEN 1 THEN '-----------------------------------' - WHEN 2 THEN - CASE - WHEN CHARINDEX('Formatted/Non:', column_info) = 1 THEN - SUBSTRING(column_info, CHARINDEX(']', column_info)+2, LEN(column_info)) - ELSE - SUBSTRING(column_info, CHARINDEX(']', column_info)+2, CHARINDEX('Non-Formatted:', column_info, CHARINDEX(']', column_info)+2) - CHARINDEX(']', column_info)-3) - END - ELSE '' - END AS formatted_column_type, - CASE output_group_order - WHEN 1 THEN '---------------------------------------' - WHEN 2 THEN - CASE - WHEN CHARINDEX('Formatted/Non:', column_info) = 1 THEN '' - ELSE - CASE - WHEN SUBSTRING(column_info, CHARINDEX(CHAR(255) COLLATE Latin1_General_Bin2, column_info, CHARINDEX('Non-Formatted:', column_info))+1, 1) = '<' THEN - SUBSTRING(column_info, CHARINDEX(CHAR(255) COLLATE Latin1_General_Bin2, column_info, CHARINDEX('Non-Formatted:', column_info))+1, CHARINDEX('>', column_info, CHARINDEX(CHAR(255) COLLATE Latin1_General_Bin2, column_info, CHARINDEX('Non-Formatted:', column_info))+1) - CHARINDEX(CHAR(255) COLLATE Latin1_General_Bin2, column_info, CHARINDEX('Non-Formatted:', column_info))) - ELSE - SUBSTRING(column_info, CHARINDEX(CHAR(255) COLLATE Latin1_General_Bin2, column_info, CHARINDEX('Non-Formatted:', column_info))+1, CHARINDEX(']', column_info, CHARINDEX(CHAR(255) COLLATE Latin1_General_Bin2, column_info, CHARINDEX('Non-Formatted:', column_info))+1) - CHARINDEX(CHAR(255) COLLATE Latin1_General_Bin2, column_info, CHARINDEX('Non-Formatted:', column_info))) - END - END - ELSE '' - END AS unformatted_column_name, - CASE output_group_order - WHEN 1 THEN '---------------------------------------' - WHEN 2 THEN - CASE - WHEN CHARINDEX('Formatted/Non:', column_info) = 1 THEN '' - ELSE - CASE - WHEN SUBSTRING(column_info, CHARINDEX(CHAR(255) COLLATE Latin1_General_Bin2, column_info, CHARINDEX('Non-Formatted:', column_info))+1, 1) = '<' THEN '' - ELSE - SUBSTRING(column_info, CHARINDEX(']', column_info, CHARINDEX('Non-Formatted:', column_info))+2, CHARINDEX('Non-Formatted:', column_info, CHARINDEX(']', column_info)+2) - CHARINDEX(']', column_info)-3) - END - END - ELSE '' - END AS unformatted_column_type, - CASE output_group_order - WHEN 1 THEN '----------------------------------------------------------------------------------------------------------------------' - ELSE REPLACE(token, CHAR(255) COLLATE Latin1_General_Bin2, '') - END AS [------description-----------------------------------------------------------------------------------------------------] - FROM output_tokens - WHERE - NOT - ( - output_group_order = 1 - AND output_group = LEN(@outputs) - ) - ORDER BY - output_group, - CASE output_group_order - WHEN 1 THEN 99 - ELSE output_group_order - END; - - RETURN; - END; - - WITH - a0 AS - (SELECT 1 AS n UNION ALL SELECT 1), - a1 AS - (SELECT 1 AS n FROM a0 AS a, a0 AS b), - a2 AS - (SELECT 1 AS n FROM a1 AS a, a1 AS b), - a3 AS - (SELECT 1 AS n FROM a2 AS a, a2 AS b), - a4 AS - (SELECT 1 AS n FROM a3 AS a, a3 AS b), - numbers AS - ( - SELECT TOP(LEN(@output_column_list)) - ROW_NUMBER() OVER - ( - ORDER BY (SELECT NULL) - ) AS number - FROM a4 - ORDER BY - number - ), - tokens AS - ( - SELECT - '|[' + - SUBSTRING - ( - @output_column_list, - number + 1, - CHARINDEX(']', @output_column_list, number) - number - 1 - ) + '|]' AS token, - number - FROM numbers - WHERE - SUBSTRING(@output_column_list, number, 1) = '[' - ), - ordered_columns AS - ( - SELECT - x.column_name, - ROW_NUMBER() OVER - ( - PARTITION BY - x.column_name - ORDER BY - tokens.number, - x.default_order - ) AS r, - ROW_NUMBER() OVER - ( - ORDER BY - tokens.number, - x.default_order - ) AS s - FROM tokens - JOIN - ( - SELECT '[session_id]' AS column_name, 1 AS default_order - UNION ALL - SELECT '[dd hh:mm:ss.mss]', 2 - WHERE - @format_output IN (1, 2) - UNION ALL - SELECT '[dd hh:mm:ss.mss (avg)]', 3 - WHERE - @format_output IN (1, 2) - AND @get_avg_time = 1 - UNION ALL - SELECT '[avg_elapsed_time]', 4 - WHERE - @format_output = 0 - AND @get_avg_time = 1 - UNION ALL - SELECT '[physical_io]', 5 - WHERE - @get_task_info = 2 - UNION ALL - SELECT '[reads]', 6 - UNION ALL - SELECT '[physical_reads]', 7 - UNION ALL - SELECT '[writes]', 8 - UNION ALL - SELECT '[tempdb_allocations]', 9 - UNION ALL - SELECT '[tempdb_current]', 10 - UNION ALL - SELECT '[CPU]', 11 - UNION ALL - SELECT '[context_switches]', 12 - WHERE - @get_task_info = 2 - UNION ALL - SELECT '[used_memory]', 13 - UNION ALL - SELECT '[physical_io_delta]', 14 - WHERE - @delta_interval > 0 - AND @get_task_info = 2 - UNION ALL - SELECT '[reads_delta]', 15 - WHERE - @delta_interval > 0 - UNION ALL - SELECT '[physical_reads_delta]', 16 - WHERE - @delta_interval > 0 - UNION ALL - SELECT '[writes_delta]', 17 - WHERE - @delta_interval > 0 - UNION ALL - SELECT '[tempdb_allocations_delta]', 18 - WHERE - @delta_interval > 0 - UNION ALL - SELECT '[tempdb_current_delta]', 19 - WHERE - @delta_interval > 0 - UNION ALL - SELECT '[CPU_delta]', 20 - WHERE - @delta_interval > 0 - UNION ALL - SELECT '[context_switches_delta]', 21 - WHERE - @delta_interval > 0 - AND @get_task_info = 2 - UNION ALL - SELECT '[used_memory_delta]', 22 - WHERE - @delta_interval > 0 - UNION ALL - SELECT '[tasks]', 23 - WHERE - @get_task_info = 2 - UNION ALL - SELECT '[status]', 24 - UNION ALL - SELECT '[wait_info]', 25 - WHERE - @get_task_info > 0 - OR @find_block_leaders = 1 - UNION ALL - SELECT '[locks]', 26 - WHERE - @get_locks = 1 - UNION ALL - SELECT '[tran_start_time]', 27 - WHERE - @get_transaction_info = 1 - UNION ALL - SELECT '[tran_log_writes]', 28 - WHERE - @get_transaction_info = 1 - UNION ALL - SELECT '[open_tran_count]', 29 - UNION ALL - SELECT '[sql_command]', 30 - WHERE - @get_outer_command = 1 - UNION ALL - SELECT '[sql_text]', 31 - UNION ALL - SELECT '[query_plan]', 32 - WHERE - @get_plans >= 1 - UNION ALL - SELECT '[blocking_session_id]', 33 - WHERE - @get_task_info > 0 - OR @find_block_leaders = 1 - UNION ALL - SELECT '[blocked_session_count]', 34 - WHERE - @find_block_leaders = 1 - UNION ALL - SELECT '[percent_complete]', 35 - UNION ALL - SELECT '[host_name]', 36 - UNION ALL - SELECT '[login_name]', 37 - UNION ALL - SELECT '[database_name]', 38 - UNION ALL - SELECT '[program_name]', 39 - UNION ALL - SELECT '[additional_info]', 40 - WHERE - @get_additional_info = 1 - UNION ALL - SELECT '[start_time]', 41 - UNION ALL - SELECT '[login_time]', 42 - UNION ALL - SELECT '[request_id]', 43 - UNION ALL - SELECT '[collection_time]', 44 - ) AS x ON - x.column_name LIKE token ESCAPE '|' - ) - SELECT - @output_column_list = - STUFF - ( - ( - SELECT - ',' + column_name as [text()] - FROM ordered_columns - WHERE - r = 1 - ORDER BY - s - FOR XML - PATH('') - ), - 1, - 1, - '' - ); - - IF COALESCE(RTRIM(@output_column_list), '') = '' - BEGIN; - RAISERROR('No valid column matches found in @output_column_list or no columns remain due to selected options.', 16, 1); - RETURN; - END; - - IF @destination_table <> '' - BEGIN; - SET @destination_table = - --database - COALESCE(QUOTENAME(PARSENAME(@destination_table, 3)) + '.', '') + - --schema - COALESCE(QUOTENAME(PARSENAME(@destination_table, 2)) + '.', '') + - --table - COALESCE(QUOTENAME(PARSENAME(@destination_table, 1)), ''); - - IF COALESCE(RTRIM(@destination_table), '') = '' - BEGIN; - RAISERROR('Destination table not properly formatted.', 16, 1); - RETURN; - END; - END; - - WITH - a0 AS - (SELECT 1 AS n UNION ALL SELECT 1), - a1 AS - (SELECT 1 AS n FROM a0 AS a, a0 AS b), - a2 AS - (SELECT 1 AS n FROM a1 AS a, a1 AS b), - a3 AS - (SELECT 1 AS n FROM a2 AS a, a2 AS b), - a4 AS - (SELECT 1 AS n FROM a3 AS a, a3 AS b), - numbers AS - ( - SELECT TOP(LEN(@sort_order)) - ROW_NUMBER() OVER - ( - ORDER BY (SELECT NULL) - ) AS number - FROM a4 - ORDER BY - number - ), - tokens AS - ( - SELECT - '|[' + - SUBSTRING - ( - @sort_order, - number + 1, - CHARINDEX(']', @sort_order, number) - number - 1 - ) + '|]' AS token, - SUBSTRING - ( - @sort_order, - CHARINDEX(']', @sort_order, number) + 1, - COALESCE(NULLIF(CHARINDEX('[', @sort_order, CHARINDEX(']', @sort_order, number)), 0), LEN(@sort_order)) - CHARINDEX(']', @sort_order, number) - ) AS next_chunk, - number - FROM numbers - WHERE - SUBSTRING(@sort_order, number, 1) = '[' - ), - ordered_columns AS - ( - SELECT - x.column_name + - CASE - WHEN tokens.next_chunk LIKE '%asc%' THEN ' ASC' - WHEN tokens.next_chunk LIKE '%desc%' THEN ' DESC' - ELSE '' - END AS column_name, - ROW_NUMBER() OVER - ( - PARTITION BY - x.column_name - ORDER BY - tokens.number - ) AS r, - tokens.number - FROM tokens - JOIN - ( - SELECT '[session_id]' AS column_name - UNION ALL - SELECT '[physical_io]' - UNION ALL - SELECT '[reads]' - UNION ALL - SELECT '[physical_reads]' - UNION ALL - SELECT '[writes]' - UNION ALL - SELECT '[tempdb_allocations]' - UNION ALL - SELECT '[tempdb_current]' - UNION ALL - SELECT '[CPU]' - UNION ALL - SELECT '[context_switches]' - UNION ALL - SELECT '[used_memory]' - UNION ALL - SELECT '[physical_io_delta]' - UNION ALL - SELECT '[reads_delta]' - UNION ALL - SELECT '[physical_reads_delta]' - UNION ALL - SELECT '[writes_delta]' - UNION ALL - SELECT '[tempdb_allocations_delta]' - UNION ALL - SELECT '[tempdb_current_delta]' - UNION ALL - SELECT '[CPU_delta]' - UNION ALL - SELECT '[context_switches_delta]' - UNION ALL - SELECT '[used_memory_delta]' - UNION ALL - SELECT '[tasks]' - UNION ALL - SELECT '[tran_start_time]' - UNION ALL - SELECT '[open_tran_count]' - UNION ALL - SELECT '[blocking_session_id]' - UNION ALL - SELECT '[blocked_session_count]' - UNION ALL - SELECT '[percent_complete]' - UNION ALL - SELECT '[host_name]' - UNION ALL - SELECT '[login_name]' - UNION ALL - SELECT '[database_name]' - UNION ALL - SELECT '[start_time]' - UNION ALL - SELECT '[login_time]' - ) AS x ON - x.column_name LIKE token ESCAPE '|' - ) - SELECT - @sort_order = COALESCE(z.sort_order, '') - FROM - ( - SELECT - STUFF - ( - ( - SELECT - ',' + column_name as [text()] - FROM ordered_columns - WHERE - r = 1 - ORDER BY - number - FOR XML - PATH('') - ), - 1, - 1, - '' - ) AS sort_order - ) AS z; - - CREATE TABLE #sessions - ( - recursion SMALLINT NOT NULL, - session_id SMALLINT NOT NULL, - request_id INT NOT NULL, - session_number INT NOT NULL, - elapsed_time INT NOT NULL, - avg_elapsed_time INT NULL, - physical_io BIGINT NULL, - reads BIGINT NULL, - physical_reads BIGINT NULL, - writes BIGINT NULL, - tempdb_allocations BIGINT NULL, - tempdb_current BIGINT NULL, - CPU INT NULL, - thread_CPU_snapshot BIGINT NULL, - context_switches BIGINT NULL, - used_memory BIGINT NOT NULL, - tasks SMALLINT NULL, - status VARCHAR(30) NOT NULL, - wait_info NVARCHAR(4000) NULL, - locks XML NULL, - transaction_id BIGINT NULL, - tran_start_time DATETIME NULL, - tran_log_writes NVARCHAR(4000) NULL, - open_tran_count SMALLINT NULL, - sql_command XML NULL, - sql_handle VARBINARY(64) NULL, - statement_start_offset INT NULL, - statement_end_offset INT NULL, - sql_text XML NULL, - plan_handle VARBINARY(64) NULL, - query_plan XML NULL, - blocking_session_id SMALLINT NULL, - blocked_session_count SMALLINT NULL, - percent_complete REAL NULL, - host_name sysname NULL, - login_name sysname NOT NULL, - database_name sysname NULL, - program_name sysname NULL, - additional_info XML NULL, - start_time DATETIME NOT NULL, - login_time DATETIME NULL, - last_request_start_time DATETIME NULL, - PRIMARY KEY CLUSTERED (session_id, request_id, recursion) WITH (IGNORE_DUP_KEY = ON), - UNIQUE NONCLUSTERED (transaction_id, session_id, request_id, recursion) WITH (IGNORE_DUP_KEY = ON) - ); - - IF @return_schema = 0 - BEGIN; - --Disable unnecessary autostats on the table - CREATE STATISTICS s_session_id ON #sessions (session_id) - WITH SAMPLE 0 ROWS, NORECOMPUTE; - CREATE STATISTICS s_request_id ON #sessions (request_id) - WITH SAMPLE 0 ROWS, NORECOMPUTE; - CREATE STATISTICS s_transaction_id ON #sessions (transaction_id) - WITH SAMPLE 0 ROWS, NORECOMPUTE; - CREATE STATISTICS s_session_number ON #sessions (session_number) - WITH SAMPLE 0 ROWS, NORECOMPUTE; - CREATE STATISTICS s_status ON #sessions (status) - WITH SAMPLE 0 ROWS, NORECOMPUTE; - CREATE STATISTICS s_start_time ON #sessions (start_time) - WITH SAMPLE 0 ROWS, NORECOMPUTE; - CREATE STATISTICS s_last_request_start_time ON #sessions (last_request_start_time) - WITH SAMPLE 0 ROWS, NORECOMPUTE; - CREATE STATISTICS s_recursion ON #sessions (recursion) - WITH SAMPLE 0 ROWS, NORECOMPUTE; - - DECLARE @recursion SMALLINT; - SET @recursion = - CASE @delta_interval - WHEN 0 THEN 1 - ELSE -1 - END; - - DECLARE @first_collection_ms_ticks BIGINT; - DECLARE @last_collection_start DATETIME; - - --Used for the delta pull - REDO:; - - IF - @get_locks = 1 - AND @recursion = 1 - AND @output_column_list LIKE '%|[locks|]%' ESCAPE '|' - BEGIN; - SELECT - y.resource_type, - y.database_name, - y.object_id, - y.file_id, - y.page_type, - y.hobt_id, - y.allocation_unit_id, - y.index_id, - y.schema_id, - y.principal_id, - y.request_mode, - y.request_status, - y.session_id, - y.resource_description, - y.request_count, - s.request_id, - s.start_time, - CONVERT(sysname, NULL) AS object_name, - CONVERT(sysname, NULL) AS index_name, - CONVERT(sysname, NULL) AS schema_name, - CONVERT(sysname, NULL) AS principal_name, - CONVERT(NVARCHAR(2048), NULL) AS query_error - INTO #locks - FROM - ( - SELECT - sp.spid AS session_id, - CASE sp.status - WHEN 'sleeping' THEN CONVERT(INT, 0) - ELSE sp.request_id - END AS request_id, - CASE sp.status - WHEN 'sleeping' THEN sp.last_batch - ELSE COALESCE(req.start_time, sp.last_batch) - END AS start_time, - sp.dbid - FROM sys.sysprocesses AS sp - OUTER APPLY - ( - SELECT TOP(1) - CASE - WHEN - ( - sp.hostprocess > '' - OR r.total_elapsed_time < 0 - ) THEN - r.start_time - ELSE - DATEADD - ( - ms, - 1000 * (DATEPART(ms, DATEADD(second, -(r.total_elapsed_time / 1000), GETDATE())) / 500) - DATEPART(ms, DATEADD(second, -(r.total_elapsed_time / 1000), GETDATE())), - DATEADD(second, -(r.total_elapsed_time / 1000), GETDATE()) - ) - END AS start_time - FROM sys.dm_exec_requests AS r - WHERE - r.session_id = sp.spid - AND r.request_id = sp.request_id - ) AS req - WHERE - --Process inclusive filter - 1 = - CASE - WHEN @filter <> '' THEN - CASE @filter_type - WHEN 'session' THEN - CASE - WHEN - CONVERT(SMALLINT, @filter) = 0 - OR sp.spid = CONVERT(SMALLINT, @filter) - THEN 1 - ELSE 0 - END - WHEN 'program' THEN - CASE - WHEN sp.program_name LIKE @filter THEN 1 - ELSE 0 - END - WHEN 'login' THEN - CASE - WHEN sp.loginame LIKE @filter THEN 1 - ELSE 0 - END - WHEN 'host' THEN - CASE - WHEN sp.hostname LIKE @filter THEN 1 - ELSE 0 - END - WHEN 'database' THEN - CASE - WHEN DB_NAME(sp.dbid) LIKE @filter THEN 1 - ELSE 0 - END - ELSE 0 - END - ELSE 1 - END - --Process exclusive filter - AND 0 = - CASE - WHEN @not_filter <> '' THEN - CASE @not_filter_type - WHEN 'session' THEN - CASE - WHEN sp.spid = CONVERT(SMALLINT, @not_filter) THEN 1 - ELSE 0 - END - WHEN 'program' THEN - CASE - WHEN sp.program_name LIKE @not_filter THEN 1 - ELSE 0 - END - WHEN 'login' THEN - CASE - WHEN sp.loginame LIKE @not_filter THEN 1 - ELSE 0 - END - WHEN 'host' THEN - CASE - WHEN sp.hostname LIKE @not_filter THEN 1 - ELSE 0 - END - WHEN 'database' THEN - CASE - WHEN DB_NAME(sp.dbid) LIKE @not_filter THEN 1 - ELSE 0 - END - ELSE 0 - END - ELSE 0 - END - AND - ( - @show_own_spid = 1 - OR sp.spid <> @@SPID - ) - AND - ( - @show_system_spids = 1 - OR sp.hostprocess > '' - ) - AND sp.ecid = 0 - ) AS s - INNER HASH JOIN - ( - SELECT - x.resource_type, - x.database_name, - x.object_id, - x.file_id, - CASE - WHEN x.page_no = 1 OR x.page_no % 8088 = 0 THEN 'PFS' - WHEN x.page_no = 2 OR x.page_no % 511232 = 0 THEN 'GAM' - WHEN x.page_no = 3 OR (x.page_no - 1) % 511232 = 0 THEN 'SGAM' - WHEN x.page_no = 6 OR (x.page_no - 6) % 511232 = 0 THEN 'DCM' - WHEN x.page_no = 7 OR (x.page_no - 7) % 511232 = 0 THEN 'BCM' - WHEN x.page_no IS NOT NULL THEN '*' - ELSE NULL - END AS page_type, - x.hobt_id, - x.allocation_unit_id, - x.index_id, - x.schema_id, - x.principal_id, - x.request_mode, - x.request_status, - x.session_id, - x.request_id, - CASE - WHEN COALESCE(x.object_id, x.file_id, x.hobt_id, x.allocation_unit_id, x.index_id, x.schema_id, x.principal_id) IS NULL THEN NULLIF(resource_description, '') - ELSE NULL - END AS resource_description, - COUNT(*) AS request_count - FROM - ( - SELECT - tl.resource_type + - CASE - WHEN tl.resource_subtype = '' THEN '' - ELSE '.' + tl.resource_subtype - END AS resource_type, - COALESCE(DB_NAME(tl.resource_database_id), N'(null)') AS database_name, - CONVERT - ( - INT, - CASE - WHEN tl.resource_type = 'OBJECT' THEN tl.resource_associated_entity_id - WHEN tl.resource_description LIKE '%object_id = %' THEN - ( - SUBSTRING - ( - tl.resource_description, - (CHARINDEX('object_id = ', tl.resource_description) + 12), - COALESCE - ( - NULLIF - ( - CHARINDEX(',', tl.resource_description, CHARINDEX('object_id = ', tl.resource_description) + 12), - 0 - ), - DATALENGTH(tl.resource_description)+1 - ) - (CHARINDEX('object_id = ', tl.resource_description) + 12) - ) - ) - ELSE NULL - END - ) AS object_id, - CONVERT - ( - INT, - CASE - WHEN tl.resource_type = 'FILE' THEN CONVERT(INT, tl.resource_description) - WHEN tl.resource_type IN ('PAGE', 'EXTENT', 'RID') THEN LEFT(tl.resource_description, CHARINDEX(':', tl.resource_description)-1) - ELSE NULL - END - ) AS file_id, - CONVERT - ( - INT, - CASE - WHEN tl.resource_type IN ('PAGE', 'EXTENT', 'RID') THEN - SUBSTRING - ( - tl.resource_description, - CHARINDEX(':', tl.resource_description) + 1, - COALESCE - ( - NULLIF - ( - CHARINDEX(':', tl.resource_description, CHARINDEX(':', tl.resource_description) + 1), - 0 - ), - DATALENGTH(tl.resource_description)+1 - ) - (CHARINDEX(':', tl.resource_description) + 1) - ) - ELSE NULL - END - ) AS page_no, - CASE - WHEN tl.resource_type IN ('PAGE', 'KEY', 'RID', 'HOBT') THEN tl.resource_associated_entity_id - ELSE NULL - END AS hobt_id, - CASE - WHEN tl.resource_type = 'ALLOCATION_UNIT' THEN tl.resource_associated_entity_id - ELSE NULL - END AS allocation_unit_id, - CONVERT - ( - INT, - CASE - WHEN - /*TODO: Deal with server principals*/ - tl.resource_subtype <> 'SERVER_PRINCIPAL' - AND tl.resource_description LIKE '%index_id or stats_id = %' THEN - ( - SUBSTRING - ( - tl.resource_description, - (CHARINDEX('index_id or stats_id = ', tl.resource_description) + 23), - COALESCE - ( - NULLIF - ( - CHARINDEX(',', tl.resource_description, CHARINDEX('index_id or stats_id = ', tl.resource_description) + 23), - 0 - ), - DATALENGTH(tl.resource_description)+1 - ) - (CHARINDEX('index_id or stats_id = ', tl.resource_description) + 23) - ) - ) - ELSE NULL - END - ) AS index_id, - CONVERT - ( - INT, - CASE - WHEN tl.resource_description LIKE '%schema_id = %' THEN - ( - SUBSTRING - ( - tl.resource_description, - (CHARINDEX('schema_id = ', tl.resource_description) + 12), - COALESCE - ( - NULLIF - ( - CHARINDEX(',', tl.resource_description, CHARINDEX('schema_id = ', tl.resource_description) + 12), - 0 - ), - DATALENGTH(tl.resource_description)+1 - ) - (CHARINDEX('schema_id = ', tl.resource_description) + 12) - ) - ) - ELSE NULL - END - ) AS schema_id, - CONVERT - ( - INT, - CASE - WHEN tl.resource_description LIKE '%principal_id = %' THEN - ( - SUBSTRING - ( - tl.resource_description, - (CHARINDEX('principal_id = ', tl.resource_description) + 15), - COALESCE - ( - NULLIF - ( - CHARINDEX(',', tl.resource_description, CHARINDEX('principal_id = ', tl.resource_description) + 15), - 0 - ), - DATALENGTH(tl.resource_description)+1 - ) - (CHARINDEX('principal_id = ', tl.resource_description) + 15) - ) - ) - ELSE NULL - END - ) AS principal_id, - tl.request_mode, - tl.request_status, - tl.request_session_id AS session_id, - tl.request_request_id AS request_id, - - /*TODO: Applocks, other resource_descriptions*/ - RTRIM(tl.resource_description) AS resource_description, - tl.resource_associated_entity_id - /*********************************************/ - FROM - ( - SELECT - request_session_id, - CONVERT(VARCHAR(120), resource_type) COLLATE Latin1_General_Bin2 AS resource_type, - CONVERT(VARCHAR(120), resource_subtype) COLLATE Latin1_General_Bin2 AS resource_subtype, - resource_database_id, - CONVERT(VARCHAR(512), resource_description) COLLATE Latin1_General_Bin2 AS resource_description, - resource_associated_entity_id, - CONVERT(VARCHAR(120), request_mode) COLLATE Latin1_General_Bin2 AS request_mode, - CONVERT(VARCHAR(120), request_status) COLLATE Latin1_General_Bin2 AS request_status, - request_request_id - FROM sys.dm_tran_locks - ) AS tl - ) AS x - GROUP BY - x.resource_type, - x.database_name, - x.object_id, - x.file_id, - CASE - WHEN x.page_no = 1 OR x.page_no % 8088 = 0 THEN 'PFS' - WHEN x.page_no = 2 OR x.page_no % 511232 = 0 THEN 'GAM' - WHEN x.page_no = 3 OR (x.page_no - 1) % 511232 = 0 THEN 'SGAM' - WHEN x.page_no = 6 OR (x.page_no - 6) % 511232 = 0 THEN 'DCM' - WHEN x.page_no = 7 OR (x.page_no - 7) % 511232 = 0 THEN 'BCM' - WHEN x.page_no IS NOT NULL THEN '*' - ELSE NULL - END, - x.hobt_id, - x.allocation_unit_id, - x.index_id, - x.schema_id, - x.principal_id, - x.request_mode, - x.request_status, - x.session_id, - x.request_id, - CASE - WHEN COALESCE(x.object_id, x.file_id, x.hobt_id, x.allocation_unit_id, x.index_id, x.schema_id, x.principal_id) IS NULL THEN NULLIF(resource_description, '') - ELSE NULL - END - ) AS y ON - y.session_id = s.session_id - AND y.request_id = s.request_id - OPTION (HASH GROUP); - - --Disable unnecessary autostats on the table - CREATE STATISTICS s_database_name ON #locks (database_name) - WITH SAMPLE 0 ROWS, NORECOMPUTE; - CREATE STATISTICS s_object_id ON #locks (object_id) - WITH SAMPLE 0 ROWS, NORECOMPUTE; - CREATE STATISTICS s_hobt_id ON #locks (hobt_id) - WITH SAMPLE 0 ROWS, NORECOMPUTE; - CREATE STATISTICS s_allocation_unit_id ON #locks (allocation_unit_id) - WITH SAMPLE 0 ROWS, NORECOMPUTE; - CREATE STATISTICS s_index_id ON #locks (index_id) - WITH SAMPLE 0 ROWS, NORECOMPUTE; - CREATE STATISTICS s_schema_id ON #locks (schema_id) - WITH SAMPLE 0 ROWS, NORECOMPUTE; - CREATE STATISTICS s_principal_id ON #locks (principal_id) - WITH SAMPLE 0 ROWS, NORECOMPUTE; - CREATE STATISTICS s_request_id ON #locks (request_id) - WITH SAMPLE 0 ROWS, NORECOMPUTE; - CREATE STATISTICS s_start_time ON #locks (start_time) - WITH SAMPLE 0 ROWS, NORECOMPUTE; - CREATE STATISTICS s_resource_type ON #locks (resource_type) - WITH SAMPLE 0 ROWS, NORECOMPUTE; - CREATE STATISTICS s_object_name ON #locks (object_name) - WITH SAMPLE 0 ROWS, NORECOMPUTE; - CREATE STATISTICS s_schema_name ON #locks (schema_name) - WITH SAMPLE 0 ROWS, NORECOMPUTE; - CREATE STATISTICS s_page_type ON #locks (page_type) - WITH SAMPLE 0 ROWS, NORECOMPUTE; - CREATE STATISTICS s_request_mode ON #locks (request_mode) - WITH SAMPLE 0 ROWS, NORECOMPUTE; - CREATE STATISTICS s_request_status ON #locks (request_status) - WITH SAMPLE 0 ROWS, NORECOMPUTE; - CREATE STATISTICS s_resource_description ON #locks (resource_description) - WITH SAMPLE 0 ROWS, NORECOMPUTE; - CREATE STATISTICS s_index_name ON #locks (index_name) - WITH SAMPLE 0 ROWS, NORECOMPUTE; - CREATE STATISTICS s_principal_name ON #locks (principal_name) - WITH SAMPLE 0 ROWS, NORECOMPUTE; - END; - - DECLARE - @sql VARCHAR(MAX), - @sql_n NVARCHAR(MAX); - - SET @sql = - CONVERT(VARCHAR(MAX), '') + - 'DECLARE @blocker BIT; - SET @blocker = 0; - DECLARE @i INT; - SET @i = 2147483647; - - DECLARE @sessions TABLE - ( - session_id SMALLINT NOT NULL, - request_id INT NOT NULL, - login_time DATETIME, - last_request_end_time DATETIME, - status VARCHAR(30), - statement_start_offset INT, - statement_end_offset INT, - sql_handle BINARY(20), - host_name NVARCHAR(128), - login_name NVARCHAR(128), - program_name NVARCHAR(128), - database_id SMALLINT, - memory_usage INT, - open_tran_count SMALLINT, - ' + - CASE - WHEN - ( - @get_task_info <> 0 - OR @find_block_leaders = 1 - ) THEN - 'wait_type NVARCHAR(32), - wait_resource NVARCHAR(256), - wait_time BIGINT, - ' - ELSE - '' - END + - 'blocked SMALLINT, - is_user_process BIT, - cmd VARCHAR(32), - PRIMARY KEY CLUSTERED (session_id, request_id) WITH (IGNORE_DUP_KEY = ON) - ); - - DECLARE @blockers TABLE - ( - session_id INT NOT NULL PRIMARY KEY WITH (IGNORE_DUP_KEY = ON) - ); - - BLOCKERS:; - - INSERT @sessions - ( - session_id, - request_id, - login_time, - last_request_end_time, - status, - statement_start_offset, - statement_end_offset, - sql_handle, - host_name, - login_name, - program_name, - database_id, - memory_usage, - open_tran_count, - ' + - CASE - WHEN - ( - @get_task_info <> 0 - OR @find_block_leaders = 1 - ) THEN - 'wait_type, - wait_resource, - wait_time, - ' - ELSE - '' - END + - 'blocked, - is_user_process, - cmd - ) - SELECT TOP(@i) - spy.session_id, - spy.request_id, - spy.login_time, - spy.last_request_end_time, - spy.status, - spy.statement_start_offset, - spy.statement_end_offset, - spy.sql_handle, - spy.host_name, - spy.login_name, - spy.program_name, - spy.database_id, - spy.memory_usage, - spy.open_tran_count, - ' + - CASE - WHEN - ( - @get_task_info <> 0 - OR @find_block_leaders = 1 - ) THEN - 'spy.wait_type, - CASE - WHEN - spy.wait_type LIKE N''PAGE%LATCH_%'' - OR spy.wait_type = N''CXPACKET'' - OR spy.wait_type LIKE N''LATCH[_]%'' - OR spy.wait_type = N''OLEDB'' THEN - spy.wait_resource - ELSE - NULL - END AS wait_resource, - spy.wait_time, - ' - ELSE - '' - END + - 'spy.blocked, - spy.is_user_process, - spy.cmd - FROM - ( - SELECT TOP(@i) - spx.*, - ' + - CASE - WHEN - ( - @get_task_info <> 0 - OR @find_block_leaders = 1 - ) THEN - 'ROW_NUMBER() OVER - ( - PARTITION BY - spx.session_id, - spx.request_id - ORDER BY - CASE - WHEN spx.wait_type LIKE N''LCK[_]%'' THEN - 1 - ELSE - 99 - END, - spx.wait_time DESC, - spx.blocked DESC - ) AS r - ' - ELSE - '1 AS r - ' - END + - 'FROM - ( - SELECT TOP(@i) - sp0.session_id, - sp0.request_id, - sp0.login_time, - sp0.last_request_end_time, - LOWER(sp0.status) AS status, - CASE - WHEN sp0.cmd = ''CREATE INDEX'' THEN - 0 - ELSE - sp0.stmt_start - END AS statement_start_offset, - CASE - WHEN sp0.cmd = N''CREATE INDEX'' THEN - -1 - ELSE - COALESCE(NULLIF(sp0.stmt_end, 0), -1) - END AS statement_end_offset, - sp0.sql_handle, - sp0.host_name, - sp0.login_name, - sp0.program_name, - sp0.database_id, - sp0.memory_usage, - sp0.open_tran_count, - ' + - CASE - WHEN - ( - @get_task_info <> 0 - OR @find_block_leaders = 1 - ) THEN - 'CASE - WHEN sp0.wait_time > 0 AND sp0.wait_type <> N''CXPACKET'' THEN - sp0.wait_type - ELSE - NULL - END AS wait_type, - CASE - WHEN sp0.wait_time > 0 AND sp0.wait_type <> N''CXPACKET'' THEN - sp0.wait_resource - ELSE - NULL - END AS wait_resource, - CASE - WHEN sp0.wait_type <> N''CXPACKET'' THEN - sp0.wait_time - ELSE - 0 - END AS wait_time, - ' - ELSE - '' - END + - 'sp0.blocked, - sp0.is_user_process, - sp0.cmd - FROM - ( - SELECT TOP(@i) - sp1.session_id, - sp1.request_id, - sp1.login_time, - sp1.last_request_end_time, - sp1.status, - sp1.cmd, - sp1.stmt_start, - sp1.stmt_end, - MAX(NULLIF(sp1.sql_handle, 0x00)) OVER (PARTITION BY sp1.session_id, sp1.request_id) AS sql_handle, - sp1.host_name, - MAX(sp1.login_name) OVER (PARTITION BY sp1.session_id, sp1.request_id) AS login_name, - sp1.program_name, - sp1.database_id, - MAX(sp1.memory_usage) OVER (PARTITION BY sp1.session_id, sp1.request_id) AS memory_usage, - MAX(sp1.open_tran_count) OVER (PARTITION BY sp1.session_id, sp1.request_id) AS open_tran_count, - sp1.wait_type, - sp1.wait_resource, - sp1.wait_time, - sp1.blocked, - sp1.hostprocess, - sp1.is_user_process - FROM - ( - SELECT TOP(@i) - sp2.spid AS session_id, - CASE sp2.status - WHEN ''sleeping'' THEN - CONVERT(INT, 0) - ELSE - sp2.request_id - END AS request_id, - MAX(sp2.login_time) AS login_time, - MAX(sp2.last_batch) AS last_request_end_time, - MAX(CONVERT(VARCHAR(30), RTRIM(sp2.status)) COLLATE Latin1_General_Bin2) AS status, - MAX(CONVERT(VARCHAR(32), RTRIM(sp2.cmd)) COLLATE Latin1_General_Bin2) AS cmd, - MAX(sp2.stmt_start) AS stmt_start, - MAX(sp2.stmt_end) AS stmt_end, - MAX(sp2.sql_handle) AS sql_handle, - MAX(CONVERT(sysname, RTRIM(sp2.hostname)) COLLATE SQL_Latin1_General_CP1_CI_AS) AS host_name, - MAX(CONVERT(sysname, RTRIM(sp2.loginame)) COLLATE SQL_Latin1_General_CP1_CI_AS) AS login_name, - MAX - ( - CASE - WHEN blk.queue_id IS NOT NULL THEN - N''Service Broker - database_id: '' + CONVERT(NVARCHAR, blk.database_id) + - N'' queue_id: '' + CONVERT(NVARCHAR, blk.queue_id) - ELSE - CONVERT - ( - sysname, - RTRIM(sp2.program_name) - ) - END COLLATE SQL_Latin1_General_CP1_CI_AS - ) AS program_name, - MAX(sp2.dbid) AS database_id, - MAX(sp2.memusage) AS memory_usage, - MAX(sp2.open_tran) AS open_tran_count, - RTRIM(sp2.lastwaittype) AS wait_type, - RTRIM(sp2.waitresource) AS wait_resource, - MAX(sp2.waittime) AS wait_time, - COALESCE(NULLIF(sp2.blocked, sp2.spid), 0) AS blocked, - MAX - ( - CASE - WHEN blk.session_id = sp2.spid THEN - ''blocker'' - ELSE - RTRIM(sp2.hostprocess) - END - ) AS hostprocess, - CONVERT - ( - BIT, - MAX - ( - CASE - WHEN sp2.hostprocess > '''' THEN - 1 - ELSE - 0 - END - ) - ) AS is_user_process - FROM - ( - SELECT TOP(@i) - session_id, - CONVERT(INT, NULL) AS queue_id, - CONVERT(INT, NULL) AS database_id - FROM @blockers - - UNION ALL - - SELECT TOP(@i) - CONVERT(SMALLINT, 0), - CONVERT(INT, NULL) AS queue_id, - CONVERT(INT, NULL) AS database_id - WHERE - @blocker = 0 - - UNION ALL - - SELECT TOP(@i) - CONVERT(SMALLINT, spid), - queue_id, - database_id - FROM sys.dm_broker_activated_tasks - WHERE - @blocker = 0 - ) AS blk - INNER JOIN sys.sysprocesses AS sp2 ON - sp2.spid = blk.session_id - OR - ( - blk.session_id = 0 - AND @blocker = 0 - ) - ' + - CASE - WHEN - ( - @get_task_info = 0 - AND @find_block_leaders = 0 - ) THEN - 'WHERE - sp2.ecid = 0 - ' - ELSE - '' - END + - 'GROUP BY - sp2.spid, - CASE sp2.status - WHEN ''sleeping'' THEN - CONVERT(INT, 0) - ELSE - sp2.request_id - END, - RTRIM(sp2.lastwaittype), - RTRIM(sp2.waitresource), - COALESCE(NULLIF(sp2.blocked, sp2.spid), 0) - ) AS sp1 - ) AS sp0 - WHERE - @blocker = 1 - OR - (1=1 - ' + - --inclusive filter - CASE - WHEN @filter <> '' THEN - CASE @filter_type - WHEN 'session' THEN - CASE - WHEN CONVERT(SMALLINT, @filter) <> 0 THEN - 'AND sp0.session_id = CONVERT(SMALLINT, @filter) - ' - ELSE - '' - END - WHEN 'program' THEN - 'AND sp0.program_name LIKE @filter - ' - WHEN 'login' THEN - 'AND sp0.login_name LIKE @filter - ' - WHEN 'host' THEN - 'AND sp0.host_name LIKE @filter - ' - WHEN 'database' THEN - 'AND DB_NAME(sp0.database_id) LIKE @filter - ' - ELSE - '' - END - ELSE - '' - END + - --exclusive filter - CASE - WHEN @not_filter <> '' THEN - CASE @not_filter_type - WHEN 'session' THEN - CASE - WHEN CONVERT(SMALLINT, @not_filter) <> 0 THEN - 'AND sp0.session_id <> CONVERT(SMALLINT, @not_filter) - ' - ELSE - '' - END - WHEN 'program' THEN - 'AND sp0.program_name NOT LIKE @not_filter - ' - WHEN 'login' THEN - 'AND sp0.login_name NOT LIKE @not_filter - ' - WHEN 'host' THEN - 'AND sp0.host_name NOT LIKE @not_filter - ' - WHEN 'database' THEN - 'AND DB_NAME(sp0.database_id) NOT LIKE @not_filter - ' - ELSE - '' - END - ELSE - '' - END + - CASE @show_own_spid - WHEN 1 THEN - '' - ELSE - 'AND sp0.session_id <> @@spid - ' - END + - CASE - WHEN @show_system_spids = 0 THEN - 'AND sp0.hostprocess > '''' - ' - ELSE - '' - END + - CASE @show_sleeping_spids - WHEN 0 THEN - 'AND sp0.status <> ''sleeping'' - ' - WHEN 1 THEN - 'AND - ( - sp0.status <> ''sleeping'' - OR sp0.open_tran_count > 0 - ) - ' - ELSE - '' - END + - ') - ) AS spx - ) AS spy - WHERE - spy.r = 1; - ' + - CASE @recursion - WHEN 1 THEN - 'IF @@ROWCOUNT > 0 - BEGIN; - INSERT @blockers - ( - session_id - ) - SELECT TOP(@i) - blocked - FROM @sessions - WHERE - NULLIF(blocked, 0) IS NOT NULL - - EXCEPT - - SELECT TOP(@i) - session_id - FROM @sessions; - ' + - - CASE - WHEN - ( - @get_task_info > 0 - OR @find_block_leaders = 1 - ) THEN - 'IF @@ROWCOUNT > 0 - BEGIN; - SET @blocker = 1; - GOTO BLOCKERS; - END; - ' - ELSE - '' - END + - 'END; - ' - ELSE - '' - END + - 'SELECT TOP(@i) - @recursion AS recursion, - x.session_id, - x.request_id, - DENSE_RANK() OVER - ( - ORDER BY - x.session_id - ) AS session_number, - ' + - CASE - WHEN @output_column_list LIKE '%|[dd hh:mm:ss.mss|]%' ESCAPE '|' THEN - 'x.elapsed_time ' - ELSE - '0 ' - END + - 'AS elapsed_time, - ' + - CASE - WHEN - ( - @output_column_list LIKE '%|[dd hh:mm:ss.mss (avg)|]%' ESCAPE '|' OR - @output_column_list LIKE '%|[avg_elapsed_time|]%' ESCAPE '|' - ) - AND @recursion = 1 - THEN - 'x.avg_elapsed_time / 1000 ' - ELSE - 'NULL ' - END + - 'AS avg_elapsed_time, - ' + - CASE - WHEN - @output_column_list LIKE '%|[physical_io|]%' ESCAPE '|' - OR @output_column_list LIKE '%|[physical_io_delta|]%' ESCAPE '|' - THEN - 'x.physical_io ' - ELSE - 'NULL ' - END + - 'AS physical_io, - ' + - CASE - WHEN - @output_column_list LIKE '%|[reads|]%' ESCAPE '|' - OR @output_column_list LIKE '%|[reads_delta|]%' ESCAPE '|' - THEN - 'x.reads ' - ELSE - '0 ' - END + - 'AS reads, - ' + - CASE - WHEN - @output_column_list LIKE '%|[physical_reads|]%' ESCAPE '|' - OR @output_column_list LIKE '%|[physical_reads_delta|]%' ESCAPE '|' - THEN - 'x.physical_reads ' - ELSE - '0 ' - END + - 'AS physical_reads, - ' + - CASE - WHEN - @output_column_list LIKE '%|[writes|]%' ESCAPE '|' - OR @output_column_list LIKE '%|[writes_delta|]%' ESCAPE '|' - THEN - 'x.writes ' - ELSE - '0 ' - END + - 'AS writes, - ' + - CASE - WHEN - @output_column_list LIKE '%|[tempdb_allocations|]%' ESCAPE '|' - OR @output_column_list LIKE '%|[tempdb_allocations_delta|]%' ESCAPE '|' - THEN - 'x.tempdb_allocations ' - ELSE - '0 ' - END + - 'AS tempdb_allocations, - ' + - CASE - WHEN - @output_column_list LIKE '%|[tempdb_current|]%' ESCAPE '|' - OR @output_column_list LIKE '%|[tempdb_current_delta|]%' ESCAPE '|' - THEN - 'x.tempdb_current ' - ELSE - '0 ' - END + - 'AS tempdb_current, - ' + - CASE - WHEN - @output_column_list LIKE '%|[CPU|]%' ESCAPE '|' - OR @output_column_list LIKE '%|[CPU_delta|]%' ESCAPE '|' - THEN - 'x.CPU ' - ELSE - '0 ' - END + - 'AS CPU, - ' + - CASE - WHEN - @output_column_list LIKE '%|[CPU_delta|]%' ESCAPE '|' - AND @get_task_info = 2 - THEN - 'x.thread_CPU_snapshot ' - ELSE - '0 ' - END + - 'AS thread_CPU_snapshot, - ' + - CASE - WHEN - @output_column_list LIKE '%|[context_switches|]%' ESCAPE '|' - OR @output_column_list LIKE '%|[context_switches_delta|]%' ESCAPE '|' - THEN - 'x.context_switches ' - ELSE - 'NULL ' - END + - 'AS context_switches, - ' + - CASE - WHEN - @output_column_list LIKE '%|[used_memory|]%' ESCAPE '|' - OR @output_column_list LIKE '%|[used_memory_delta|]%' ESCAPE '|' - THEN - 'x.used_memory ' - ELSE - '0 ' - END + - 'AS used_memory, - ' + - CASE - WHEN - @output_column_list LIKE '%|[tasks|]%' ESCAPE '|' - AND @recursion = 1 - THEN - 'x.tasks ' - ELSE - 'NULL ' - END + - 'AS tasks, - ' + - CASE - WHEN - ( - @output_column_list LIKE '%|[status|]%' ESCAPE '|' - OR @output_column_list LIKE '%|[sql_command|]%' ESCAPE '|' - ) - AND @recursion = 1 - THEN - 'x.status ' - ELSE - ''''' ' - END + - 'AS status, - ' + - CASE - WHEN - @output_column_list LIKE '%|[wait_info|]%' ESCAPE '|' - AND @recursion = 1 - THEN - CASE @get_task_info - WHEN 2 THEN - 'COALESCE(x.task_wait_info, x.sys_wait_info) ' - ELSE - 'x.sys_wait_info ' - END - ELSE - 'NULL ' - END + - 'AS wait_info, - ' + - CASE - WHEN - ( - @output_column_list LIKE '%|[tran_start_time|]%' ESCAPE '|' - OR @output_column_list LIKE '%|[tran_log_writes|]%' ESCAPE '|' - ) - AND @recursion = 1 - THEN - 'x.transaction_id ' - ELSE - 'NULL ' - END + - 'AS transaction_id, - ' + - CASE - WHEN - @output_column_list LIKE '%|[open_tran_count|]%' ESCAPE '|' - AND @recursion = 1 - THEN - 'x.open_tran_count ' - ELSE - 'NULL ' - END + - 'AS open_tran_count, - ' + - CASE - WHEN - @output_column_list LIKE '%|[sql_text|]%' ESCAPE '|' - AND @recursion = 1 - THEN - 'x.sql_handle ' - ELSE - 'NULL ' - END + - 'AS sql_handle, - ' + - CASE - WHEN - ( - @output_column_list LIKE '%|[sql_text|]%' ESCAPE '|' - OR @output_column_list LIKE '%|[query_plan|]%' ESCAPE '|' - ) - AND @recursion = 1 - THEN - 'x.statement_start_offset ' - ELSE - 'NULL ' - END + - 'AS statement_start_offset, - ' + - CASE - WHEN - ( - @output_column_list LIKE '%|[sql_text|]%' ESCAPE '|' - OR @output_column_list LIKE '%|[query_plan|]%' ESCAPE '|' - ) - AND @recursion = 1 - THEN - 'x.statement_end_offset ' - ELSE - 'NULL ' - END + - 'AS statement_end_offset, - ' + - 'NULL AS sql_text, - ' + - CASE - WHEN - @output_column_list LIKE '%|[query_plan|]%' ESCAPE '|' - AND @recursion = 1 - THEN - 'x.plan_handle ' - ELSE - 'NULL ' - END + - 'AS plan_handle, - ' + - CASE - WHEN - @output_column_list LIKE '%|[blocking_session_id|]%' ESCAPE '|' - AND @recursion = 1 - THEN - 'NULLIF(x.blocking_session_id, 0) ' - ELSE - 'NULL ' - END + - 'AS blocking_session_id, - ' + - CASE - WHEN - @output_column_list LIKE '%|[percent_complete|]%' ESCAPE '|' - AND @recursion = 1 - THEN - 'x.percent_complete ' - ELSE - 'NULL ' - END + - 'AS percent_complete, - ' + - CASE - WHEN - @output_column_list LIKE '%|[host_name|]%' ESCAPE '|' - AND @recursion = 1 - THEN - 'x.host_name ' - ELSE - ''''' ' - END + - 'AS host_name, - ' + - CASE - WHEN - @output_column_list LIKE '%|[login_name|]%' ESCAPE '|' - AND @recursion = 1 - THEN - 'x.login_name ' - ELSE - ''''' ' - END + - 'AS login_name, - ' + - CASE - WHEN - @output_column_list LIKE '%|[database_name|]%' ESCAPE '|' - AND @recursion = 1 - THEN - 'DB_NAME(x.database_id) ' - ELSE - 'NULL ' - END + - 'AS database_name, - ' + - CASE - WHEN - @output_column_list LIKE '%|[program_name|]%' ESCAPE '|' - AND @recursion = 1 - THEN - 'x.program_name ' - ELSE - ''''' ' - END + - 'AS program_name, - ' + - CASE - WHEN - @output_column_list LIKE '%|[additional_info|]%' ESCAPE '|' - AND @recursion = 1 - THEN - '( - SELECT TOP(@i) - x.text_size, - x.language, - x.date_format, - x.date_first, - CASE x.quoted_identifier - WHEN 0 THEN ''OFF'' - WHEN 1 THEN ''ON'' - END AS quoted_identifier, - CASE x.arithabort - WHEN 0 THEN ''OFF'' - WHEN 1 THEN ''ON'' - END AS arithabort, - CASE x.ansi_null_dflt_on - WHEN 0 THEN ''OFF'' - WHEN 1 THEN ''ON'' - END AS ansi_null_dflt_on, - CASE x.ansi_defaults - WHEN 0 THEN ''OFF'' - WHEN 1 THEN ''ON'' - END AS ansi_defaults, - CASE x.ansi_warnings - WHEN 0 THEN ''OFF'' - WHEN 1 THEN ''ON'' - END AS ansi_warnings, - CASE x.ansi_padding - WHEN 0 THEN ''OFF'' - WHEN 1 THEN ''ON'' - END AS ansi_padding, - CASE ansi_nulls - WHEN 0 THEN ''OFF'' - WHEN 1 THEN ''ON'' - END AS ansi_nulls, - CASE x.concat_null_yields_null - WHEN 0 THEN ''OFF'' - WHEN 1 THEN ''ON'' - END AS concat_null_yields_null, - CASE x.transaction_isolation_level - WHEN 0 THEN ''Unspecified'' - WHEN 1 THEN ''ReadUncomitted'' - WHEN 2 THEN ''ReadCommitted'' - WHEN 3 THEN ''Repeatable'' - WHEN 4 THEN ''Serializable'' - WHEN 5 THEN ''Snapshot'' - END AS transaction_isolation_level, - x.lock_timeout, - x.deadlock_priority, - x.row_count, - x.command_type, - master.dbo.fn_varbintohexstr(x.sql_handle) AS sql_handle, - master.dbo.fn_varbintohexstr(x.plan_handle) AS plan_handle, - ' + - CASE - WHEN @output_column_list LIKE '%|[program_name|]%' ESCAPE '|' THEN - '( - SELECT TOP(1) - CONVERT(uniqueidentifier, CONVERT(XML, '''').value(''xs:hexBinary( substring(sql:column("agent_info.job_id_string"), 0) )'', ''binary(16)'')) AS job_id, - agent_info.step_id, - ( - SELECT TOP(1) - NULL - FOR XML - PATH(''job_name''), - TYPE - ), - ( - SELECT TOP(1) - NULL - FOR XML - PATH(''step_name''), - TYPE - ) - FROM - ( - SELECT TOP(1) - SUBSTRING(x.program_name, CHARINDEX(''0x'', x.program_name) + 2, 32) AS job_id_string, - SUBSTRING(x.program_name, CHARINDEX('': Step '', x.program_name) + 7, CHARINDEX('')'', x.program_name, CHARINDEX('': Step '', x.program_name)) - (CHARINDEX('': Step '', x.program_name) + 7)) AS step_id - WHERE - x.program_name LIKE N''SQLAgent - TSQL JobStep (Job 0x%'' - ) AS agent_info - FOR XML - PATH(''agent_job_info''), - TYPE - ), - ' - ELSE '' - END + - CASE - WHEN @get_task_info = 2 THEN - 'CONVERT(XML, x.block_info) AS block_info, - ' - ELSE - '' - END + - 'x.host_process_id - FOR XML - PATH(''additional_info''), - TYPE - ) ' - ELSE - 'NULL ' - END + - 'AS additional_info, - x.start_time, - ' + - CASE - WHEN - @output_column_list LIKE '%|[login_time|]%' ESCAPE '|' - AND @recursion = 1 - THEN - 'x.login_time ' - ELSE - 'NULL ' - END + - 'AS login_time, - x.last_request_start_time - FROM - ( - SELECT TOP(@i) - y.*, - CASE - WHEN DATEDIFF(hour, y.start_time, GETDATE()) > 576 THEN - DATEDIFF(second, GETDATE(), y.start_time) - ELSE DATEDIFF(ms, y.start_time, GETDATE()) - END AS elapsed_time, - COALESCE(tempdb_info.tempdb_allocations, 0) AS tempdb_allocations, - COALESCE - ( - CASE - WHEN tempdb_info.tempdb_current < 0 THEN 0 - ELSE tempdb_info.tempdb_current - END, - 0 - ) AS tempdb_current, - ' + - CASE - WHEN - ( - @get_task_info <> 0 - OR @find_block_leaders = 1 - ) THEN - 'N''('' + CONVERT(NVARCHAR, y.wait_duration_ms) + N''ms)'' + - y.wait_type + - CASE - WHEN y.wait_type LIKE N''PAGE%LATCH_%'' THEN - N'':'' + - COALESCE(DB_NAME(CONVERT(INT, LEFT(y.resource_description, CHARINDEX(N'':'', y.resource_description) - 1))), N''(null)'') + - N'':'' + - SUBSTRING(y.resource_description, CHARINDEX(N'':'', y.resource_description) + 1, LEN(y.resource_description) - CHARINDEX(N'':'', REVERSE(y.resource_description)) - CHARINDEX(N'':'', y.resource_description)) + - N''('' + - CASE - WHEN - CONVERT(INT, RIGHT(y.resource_description, CHARINDEX(N'':'', REVERSE(y.resource_description)) - 1)) = 1 OR - CONVERT(INT, RIGHT(y.resource_description, CHARINDEX(N'':'', REVERSE(y.resource_description)) - 1)) % 8088 = 0 - THEN - N''PFS'' - WHEN - CONVERT(INT, RIGHT(y.resource_description, CHARINDEX(N'':'', REVERSE(y.resource_description)) - 1)) = 2 OR - CONVERT(INT, RIGHT(y.resource_description, CHARINDEX(N'':'', REVERSE(y.resource_description)) - 1)) % 511232 = 0 - THEN - N''GAM'' - WHEN - CONVERT(INT, RIGHT(y.resource_description, CHARINDEX(N'':'', REVERSE(y.resource_description)) - 1)) = 3 OR - (CONVERT(INT, RIGHT(y.resource_description, CHARINDEX(N'':'', REVERSE(y.resource_description)) - 1)) - 1) % 511232 = 0 - THEN - N''SGAM'' - WHEN - CONVERT(INT, RIGHT(y.resource_description, CHARINDEX(N'':'', REVERSE(y.resource_description)) - 1)) = 6 OR - (CONVERT(INT, RIGHT(y.resource_description, CHARINDEX(N'':'', REVERSE(y.resource_description)) - 1)) - 6) % 511232 = 0 - THEN - N''DCM'' - WHEN - CONVERT(INT, RIGHT(y.resource_description, CHARINDEX(N'':'', REVERSE(y.resource_description)) - 1)) = 7 OR - (CONVERT(INT, RIGHT(y.resource_description, CHARINDEX(N'':'', REVERSE(y.resource_description)) - 1)) - 7) % 511232 = 0 - THEN - N''BCM'' - ELSE - N''*'' - END + - N'')'' - WHEN y.wait_type = N''CXPACKET'' THEN - N'':'' + SUBSTRING(y.resource_description, CHARINDEX(N''nodeId'', y.resource_description) + 7, 4) - WHEN y.wait_type LIKE N''LATCH[_]%'' THEN - N'' ['' + LEFT(y.resource_description, COALESCE(NULLIF(CHARINDEX(N'' '', y.resource_description), 0), LEN(y.resource_description) + 1) - 1) + N'']'' - WHEN - y.wait_type = N''OLEDB'' - AND y.resource_description LIKE N''%(SPID=%)'' THEN - N''['' + LEFT(y.resource_description, CHARINDEX(N''(SPID='', y.resource_description) - 2) + - N'':'' + SUBSTRING(y.resource_description, CHARINDEX(N''(SPID='', y.resource_description) + 6, CHARINDEX(N'')'', y.resource_description, (CHARINDEX(N''(SPID='', y.resource_description) + 6)) - (CHARINDEX(N''(SPID='', y.resource_description) + 6)) + '']'' - ELSE - N'''' - END COLLATE Latin1_General_Bin2 AS sys_wait_info, - ' - ELSE - '' - END + - CASE - WHEN @get_task_info = 2 THEN - 'tasks.physical_io, - tasks.context_switches, - tasks.tasks, - tasks.block_info, - tasks.wait_info AS task_wait_info, - tasks.thread_CPU_snapshot, - ' - ELSE - '' - END + - CASE - WHEN NOT (@get_avg_time = 1 AND @recursion = 1) THEN - 'CONVERT(INT, NULL) ' - ELSE - 'qs.total_elapsed_time / qs.execution_count ' - END + - 'AS avg_elapsed_time - FROM - ( - SELECT TOP(@i) - sp.session_id, - sp.request_id, - COALESCE(r.logical_reads, s.logical_reads) AS reads, - COALESCE(r.reads, s.reads) AS physical_reads, - COALESCE(r.writes, s.writes) AS writes, - COALESCE(r.CPU_time, s.CPU_time) AS CPU, - sp.memory_usage + COALESCE(r.granted_query_memory, 0) AS used_memory, - LOWER(sp.status) AS status, - COALESCE(r.sql_handle, sp.sql_handle) AS sql_handle, - COALESCE(r.statement_start_offset, sp.statement_start_offset) AS statement_start_offset, - COALESCE(r.statement_end_offset, sp.statement_end_offset) AS statement_end_offset, - ' + - CASE - WHEN - ( - @get_task_info <> 0 - OR @find_block_leaders = 1 - ) THEN - 'sp.wait_type COLLATE Latin1_General_Bin2 AS wait_type, - sp.wait_resource COLLATE Latin1_General_Bin2 AS resource_description, - sp.wait_time AS wait_duration_ms, - ' - ELSE - '' - END + - 'NULLIF(sp.blocked, 0) AS blocking_session_id, - r.plan_handle, - NULLIF(r.percent_complete, 0) AS percent_complete, - sp.host_name, - sp.login_name, - sp.program_name, - s.host_process_id, - COALESCE(r.text_size, s.text_size) AS text_size, - COALESCE(r.language, s.language) AS language, - COALESCE(r.date_format, s.date_format) AS date_format, - COALESCE(r.date_first, s.date_first) AS date_first, - COALESCE(r.quoted_identifier, s.quoted_identifier) AS quoted_identifier, - COALESCE(r.arithabort, s.arithabort) AS arithabort, - COALESCE(r.ansi_null_dflt_on, s.ansi_null_dflt_on) AS ansi_null_dflt_on, - COALESCE(r.ansi_defaults, s.ansi_defaults) AS ansi_defaults, - COALESCE(r.ansi_warnings, s.ansi_warnings) AS ansi_warnings, - COALESCE(r.ansi_padding, s.ansi_padding) AS ansi_padding, - COALESCE(r.ansi_nulls, s.ansi_nulls) AS ansi_nulls, - COALESCE(r.concat_null_yields_null, s.concat_null_yields_null) AS concat_null_yields_null, - COALESCE(r.transaction_isolation_level, s.transaction_isolation_level) AS transaction_isolation_level, - COALESCE(r.lock_timeout, s.lock_timeout) AS lock_timeout, - COALESCE(r.deadlock_priority, s.deadlock_priority) AS deadlock_priority, - COALESCE(r.row_count, s.row_count) AS row_count, - COALESCE(r.command, sp.cmd) AS command_type, - COALESCE - ( - CASE - WHEN - ( - s.is_user_process = 0 - AND r.total_elapsed_time >= 0 - ) THEN - DATEADD - ( - ms, - 1000 * (DATEPART(ms, DATEADD(second, -(r.total_elapsed_time / 1000), GETDATE())) / 500) - DATEPART(ms, DATEADD(second, -(r.total_elapsed_time / 1000), GETDATE())), - DATEADD(second, -(r.total_elapsed_time / 1000), GETDATE()) - ) - END, - NULLIF(COALESCE(r.start_time, sp.last_request_end_time), CONVERT(DATETIME, ''19000101'', 112)), - ( - SELECT TOP(1) - DATEADD(second, -(ms_ticks / 1000), GETDATE()) - FROM sys.dm_os_sys_info - ) - ) AS start_time, - sp.login_time, - CASE - WHEN s.is_user_process = 1 THEN - s.last_request_start_time - ELSE - COALESCE - ( - DATEADD - ( - ms, - 1000 * (DATEPART(ms, DATEADD(second, -(r.total_elapsed_time / 1000), GETDATE())) / 500) - DATEPART(ms, DATEADD(second, -(r.total_elapsed_time / 1000), GETDATE())), - DATEADD(second, -(r.total_elapsed_time / 1000), GETDATE()) - ), - s.last_request_start_time - ) - END AS last_request_start_time, - r.transaction_id, - sp.database_id, - sp.open_tran_count - FROM @sessions AS sp - LEFT OUTER LOOP JOIN sys.dm_exec_sessions AS s ON - s.session_id = sp.session_id - AND s.login_time = sp.login_time - LEFT OUTER LOOP JOIN sys.dm_exec_requests AS r ON - sp.status <> ''sleeping'' - AND r.session_id = sp.session_id - AND r.request_id = sp.request_id - AND - ( - ( - s.is_user_process = 0 - AND sp.is_user_process = 0 - ) - OR - ( - r.start_time = s.last_request_start_time - AND s.last_request_end_time <= sp.last_request_end_time - ) - ) - ) AS y - ' + - CASE - WHEN @get_task_info = 2 THEN - CONVERT(VARCHAR(MAX), '') + - 'LEFT OUTER HASH JOIN - ( - SELECT TOP(@i) - task_nodes.task_node.value(''(session_id/text())[1]'', ''SMALLINT'') AS session_id, - task_nodes.task_node.value(''(request_id/text())[1]'', ''INT'') AS request_id, - task_nodes.task_node.value(''(physical_io/text())[1]'', ''BIGINT'') AS physical_io, - task_nodes.task_node.value(''(context_switches/text())[1]'', ''BIGINT'') AS context_switches, - task_nodes.task_node.value(''(tasks/text())[1]'', ''INT'') AS tasks, - task_nodes.task_node.value(''(block_info/text())[1]'', ''NVARCHAR(4000)'') AS block_info, - task_nodes.task_node.value(''(waits/text())[1]'', ''NVARCHAR(4000)'') AS wait_info, - task_nodes.task_node.value(''(thread_CPU_snapshot/text())[1]'', ''BIGINT'') AS thread_CPU_snapshot - FROM - ( - SELECT TOP(@i) - CONVERT - ( - XML, - REPLACE - ( - CONVERT(NVARCHAR(MAX), tasks_raw.task_xml_raw) COLLATE Latin1_General_Bin2, - N'''', - N'', '' - ) - ) AS task_xml - FROM - ( - SELECT TOP(@i) - CASE waits.r - WHEN 1 THEN - waits.session_id - ELSE - NULL - END AS [session_id], - CASE waits.r - WHEN 1 THEN - waits.request_id - ELSE - NULL - END AS [request_id], - CASE waits.r - WHEN 1 THEN - waits.physical_io - ELSE - NULL - END AS [physical_io], - CASE waits.r - WHEN 1 THEN - waits.context_switches - ELSE - NULL - END AS [context_switches], - CASE waits.r - WHEN 1 THEN - waits.thread_CPU_snapshot - ELSE - NULL - END AS [thread_CPU_snapshot], - CASE waits.r - WHEN 1 THEN - waits.tasks - ELSE - NULL - END AS [tasks], - CASE waits.r - WHEN 1 THEN - waits.block_info - ELSE - NULL - END AS [block_info], - REPLACE - ( - REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE( - REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE( - REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE( - CONVERT - ( - NVARCHAR(MAX), - N''('' + - CONVERT(NVARCHAR, num_waits) + N''x: '' + - CASE num_waits - WHEN 1 THEN - CONVERT(NVARCHAR, min_wait_time) + N''ms'' - WHEN 2 THEN - CASE - WHEN min_wait_time <> max_wait_time THEN - CONVERT(NVARCHAR, min_wait_time) + N''/'' + CONVERT(NVARCHAR, max_wait_time) + N''ms'' - ELSE - CONVERT(NVARCHAR, max_wait_time) + N''ms'' - END - ELSE - CASE - WHEN min_wait_time <> max_wait_time THEN - CONVERT(NVARCHAR, min_wait_time) + N''/'' + CONVERT(NVARCHAR, avg_wait_time) + N''/'' + CONVERT(NVARCHAR, max_wait_time) + N''ms'' - ELSE - CONVERT(NVARCHAR, max_wait_time) + N''ms'' - END - END + - N'')'' + wait_type COLLATE Latin1_General_Bin2 - ), - NCHAR(31),N''?''),NCHAR(30),N''?''),NCHAR(29),N''?''),NCHAR(28),N''?''),NCHAR(27),N''?''),NCHAR(26),N''?''),NCHAR(25),N''?''),NCHAR(24),N''?''),NCHAR(23),N''?''),NCHAR(22),N''?''), - NCHAR(21),N''?''),NCHAR(20),N''?''),NCHAR(19),N''?''),NCHAR(18),N''?''),NCHAR(17),N''?''),NCHAR(16),N''?''),NCHAR(15),N''?''),NCHAR(14),N''?''),NCHAR(12),N''?''), - NCHAR(11),N''?''),NCHAR(8),N''?''),NCHAR(7),N''?''),NCHAR(6),N''?''),NCHAR(5),N''?''),NCHAR(4),N''?''),NCHAR(3),N''?''),NCHAR(2),N''?''),NCHAR(1),N''?''), - NCHAR(0), - N'''' - ) AS [waits] - FROM - ( - SELECT TOP(@i) - w1.*, - ROW_NUMBER() OVER - ( - PARTITION BY - w1.session_id, - w1.request_id - ORDER BY - w1.block_info DESC, - w1.num_waits DESC, - w1.wait_type - ) AS r - FROM - ( - SELECT TOP(@i) - task_info.session_id, - task_info.request_id, - task_info.physical_io, - task_info.context_switches, - task_info.thread_CPU_snapshot, - task_info.num_tasks AS tasks, - CASE - WHEN task_info.runnable_time IS NOT NULL THEN - ''RUNNABLE'' - ELSE - wt2.wait_type - END AS wait_type, - NULLIF(COUNT(COALESCE(task_info.runnable_time, wt2.waiting_task_address)), 0) AS num_waits, - MIN(COALESCE(task_info.runnable_time, wt2.wait_duration_ms)) AS min_wait_time, - AVG(COALESCE(task_info.runnable_time, wt2.wait_duration_ms)) AS avg_wait_time, - MAX(COALESCE(task_info.runnable_time, wt2.wait_duration_ms)) AS max_wait_time, - MAX(wt2.block_info) AS block_info - FROM - ( - SELECT TOP(@i) - t.session_id, - t.request_id, - SUM(CONVERT(BIGINT, t.pending_io_count)) OVER (PARTITION BY t.session_id, t.request_id) AS physical_io, - SUM(CONVERT(BIGINT, t.context_switches_count)) OVER (PARTITION BY t.session_id, t.request_id) AS context_switches, - ' + - CASE - WHEN @output_column_list LIKE '%|[CPU_delta|]%' ESCAPE '|' - THEN - 'SUM(tr.usermode_time + tr.kernel_time) OVER (PARTITION BY t.session_id, t.request_id) ' - ELSE - 'CONVERT(BIGINT, NULL) ' - END + - ' AS thread_CPU_snapshot, - COUNT(*) OVER (PARTITION BY t.session_id, t.request_id) AS num_tasks, - t.task_address, - t.task_state, - CASE - WHEN - t.task_state = ''RUNNABLE'' - AND w.runnable_time > 0 THEN - w.runnable_time - ELSE - NULL - END AS runnable_time - FROM sys.dm_os_tasks AS t - CROSS APPLY - ( - SELECT TOP(1) - sp2.session_id - FROM @sessions AS sp2 - WHERE - sp2.session_id = t.session_id - AND sp2.request_id = t.request_id - AND sp2.status <> ''sleeping'' - ) AS sp20 - LEFT OUTER HASH JOIN - ( - SELECT TOP(@i) - ( - SELECT TOP(@i) - ms_ticks - FROM sys.dm_os_sys_info - ) - - w0.wait_resumed_ms_ticks AS runnable_time, - w0.worker_address, - w0.thread_address, - w0.task_bound_ms_ticks - FROM sys.dm_os_workers AS w0 - WHERE - w0.state = ''RUNNABLE'' - OR @first_collection_ms_ticks >= w0.task_bound_ms_ticks - ) AS w ON - w.worker_address = t.worker_address - ' + - CASE - WHEN @output_column_list LIKE '%|[CPU_delta|]%' ESCAPE '|' - THEN - 'LEFT OUTER HASH JOIN sys.dm_os_threads AS tr ON - tr.thread_address = w.thread_address - AND @first_collection_ms_ticks >= w.task_bound_ms_ticks - ' - ELSE - '' - END + - ') AS task_info - LEFT OUTER HASH JOIN - ( - SELECT TOP(@i) - wt1.wait_type, - wt1.waiting_task_address, - MAX(wt1.wait_duration_ms) AS wait_duration_ms, - MAX(wt1.block_info) AS block_info - FROM - ( - SELECT DISTINCT TOP(@i) - wt.wait_type + - CASE - WHEN wt.wait_type LIKE N''PAGE%LATCH_%'' THEN - '':'' + - COALESCE(DB_NAME(CONVERT(INT, LEFT(wt.resource_description, CHARINDEX(N'':'', wt.resource_description) - 1))), N''(null)'') + - N'':'' + - SUBSTRING(wt.resource_description, CHARINDEX(N'':'', wt.resource_description) + 1, LEN(wt.resource_description) - CHARINDEX(N'':'', REVERSE(wt.resource_description)) - CHARINDEX(N'':'', wt.resource_description)) + - N''('' + - CASE - WHEN - CONVERT(INT, RIGHT(wt.resource_description, CHARINDEX(N'':'', REVERSE(wt.resource_description)) - 1)) = 1 OR - CONVERT(INT, RIGHT(wt.resource_description, CHARINDEX(N'':'', REVERSE(wt.resource_description)) - 1)) % 8088 = 0 - THEN - N''PFS'' - WHEN - CONVERT(INT, RIGHT(wt.resource_description, CHARINDEX(N'':'', REVERSE(wt.resource_description)) - 1)) = 2 OR - CONVERT(INT, RIGHT(wt.resource_description, CHARINDEX(N'':'', REVERSE(wt.resource_description)) - 1)) % 511232 = 0 - THEN - N''GAM'' - WHEN - CONVERT(INT, RIGHT(wt.resource_description, CHARINDEX(N'':'', REVERSE(wt.resource_description)) - 1)) = 3 OR - (CONVERT(INT, RIGHT(wt.resource_description, CHARINDEX(N'':'', REVERSE(wt.resource_description)) - 1)) - 1) % 511232 = 0 - THEN - N''SGAM'' - WHEN - CONVERT(INT, RIGHT(wt.resource_description, CHARINDEX(N'':'', REVERSE(wt.resource_description)) - 1)) = 6 OR - (CONVERT(INT, RIGHT(wt.resource_description, CHARINDEX(N'':'', REVERSE(wt.resource_description)) - 1)) - 6) % 511232 = 0 - THEN - N''DCM'' - WHEN - CONVERT(INT, RIGHT(wt.resource_description, CHARINDEX(N'':'', REVERSE(wt.resource_description)) - 1)) = 7 OR - (CONVERT(INT, RIGHT(wt.resource_description, CHARINDEX(N'':'', REVERSE(wt.resource_description)) - 1)) - 7) % 511232 = 0 - THEN - N''BCM'' - ELSE - N''*'' - END + - N'')'' - WHEN wt.wait_type = N''CXPACKET'' THEN - N'':'' + SUBSTRING(wt.resource_description, CHARINDEX(N''nodeId'', wt.resource_description) + 7, 4) - WHEN wt.wait_type LIKE N''LATCH[_]%'' THEN - N'' ['' + LEFT(wt.resource_description, COALESCE(NULLIF(CHARINDEX(N'' '', wt.resource_description), 0), LEN(wt.resource_description) + 1) - 1) + N'']'' - ELSE - N'''' - END COLLATE Latin1_General_Bin2 AS wait_type, - CASE - WHEN - ( - wt.blocking_session_id IS NOT NULL - AND wt.wait_type LIKE N''LCK[_]%'' - ) THEN - ( - SELECT TOP(@i) - x.lock_type, - REPLACE - ( - REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE( - REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE( - REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE( - DB_NAME - ( - CONVERT - ( - INT, - SUBSTRING(wt.resource_description, NULLIF(CHARINDEX(N''dbid='', wt.resource_description), 0) + 5, COALESCE(NULLIF(CHARINDEX(N'' '', wt.resource_description, CHARINDEX(N''dbid='', wt.resource_description) + 5), 0), LEN(wt.resource_description) + 1) - CHARINDEX(N''dbid='', wt.resource_description) - 5) - ) - ), - NCHAR(31),N''?''),NCHAR(30),N''?''),NCHAR(29),N''?''),NCHAR(28),N''?''),NCHAR(27),N''?''),NCHAR(26),N''?''),NCHAR(25),N''?''),NCHAR(24),N''?''),NCHAR(23),N''?''),NCHAR(22),N''?''), - NCHAR(21),N''?''),NCHAR(20),N''?''),NCHAR(19),N''?''),NCHAR(18),N''?''),NCHAR(17),N''?''),NCHAR(16),N''?''),NCHAR(15),N''?''),NCHAR(14),N''?''),NCHAR(12),N''?''), - NCHAR(11),N''?''),NCHAR(8),N''?''),NCHAR(7),N''?''),NCHAR(6),N''?''),NCHAR(5),N''?''),NCHAR(4),N''?''),NCHAR(3),N''?''),NCHAR(2),N''?''),NCHAR(1),N''?''), - NCHAR(0), - N'''' - ) AS database_name, - CASE x.lock_type - WHEN N''objectlock'' THEN - SUBSTRING(wt.resource_description, NULLIF(CHARINDEX(N''objid='', wt.resource_description), 0) + 6, COALESCE(NULLIF(CHARINDEX(N'' '', wt.resource_description, CHARINDEX(N''objid='', wt.resource_description) + 6), 0), LEN(wt.resource_description) + 1) - CHARINDEX(N''objid='', wt.resource_description) - 6) - ELSE - NULL - END AS object_id, - CASE x.lock_type - WHEN N''filelock'' THEN - SUBSTRING(wt.resource_description, NULLIF(CHARINDEX(N''fileid='', wt.resource_description), 0) + 7, COALESCE(NULLIF(CHARINDEX(N'' '', wt.resource_description, CHARINDEX(N''fileid='', wt.resource_description) + 7), 0), LEN(wt.resource_description) + 1) - CHARINDEX(N''fileid='', wt.resource_description) - 7) - ELSE - NULL - END AS file_id, - CASE - WHEN x.lock_type in (N''pagelock'', N''extentlock'', N''ridlock'') THEN - SUBSTRING(wt.resource_description, NULLIF(CHARINDEX(N''associatedObjectId='', wt.resource_description), 0) + 19, COALESCE(NULLIF(CHARINDEX(N'' '', wt.resource_description, CHARINDEX(N''associatedObjectId='', wt.resource_description) + 19), 0), LEN(wt.resource_description) + 1) - CHARINDEX(N''associatedObjectId='', wt.resource_description) - 19) - WHEN x.lock_type in (N''keylock'', N''hobtlock'', N''allocunitlock'') THEN - SUBSTRING(wt.resource_description, NULLIF(CHARINDEX(N''hobtid='', wt.resource_description), 0) + 7, COALESCE(NULLIF(CHARINDEX(N'' '', wt.resource_description, CHARINDEX(N''hobtid='', wt.resource_description) + 7), 0), LEN(wt.resource_description) + 1) - CHARINDEX(N''hobtid='', wt.resource_description) - 7) - ELSE - NULL - END AS hobt_id, - CASE x.lock_type - WHEN N''applicationlock'' THEN - SUBSTRING(wt.resource_description, NULLIF(CHARINDEX(N''hash='', wt.resource_description), 0) + 5, COALESCE(NULLIF(CHARINDEX(N'' '', wt.resource_description, CHARINDEX(N''hash='', wt.resource_description) + 5), 0), LEN(wt.resource_description) + 1) - CHARINDEX(N''hash='', wt.resource_description) - 5) - ELSE - NULL - END AS applock_hash, - CASE x.lock_type - WHEN N''metadatalock'' THEN - SUBSTRING(wt.resource_description, NULLIF(CHARINDEX(N''subresource='', wt.resource_description), 0) + 12, COALESCE(NULLIF(CHARINDEX(N'' '', wt.resource_description, CHARINDEX(N''subresource='', wt.resource_description) + 12), 0), LEN(wt.resource_description) + 1) - CHARINDEX(N''subresource='', wt.resource_description) - 12) - ELSE - NULL - END AS metadata_resource, - CASE x.lock_type - WHEN N''metadatalock'' THEN - SUBSTRING(wt.resource_description, NULLIF(CHARINDEX(N''classid='', wt.resource_description), 0) + 8, COALESCE(NULLIF(CHARINDEX(N'' dbid='', wt.resource_description) - CHARINDEX(N''classid='', wt.resource_description), 0), LEN(wt.resource_description) + 1) - 8) - ELSE - NULL - END AS metadata_class_id - FROM - ( - SELECT TOP(1) - LEFT(wt.resource_description, CHARINDEX(N'' '', wt.resource_description) - 1) COLLATE Latin1_General_Bin2 AS lock_type - ) AS x - FOR XML - PATH('''') - ) - ELSE NULL - END AS block_info, - wt.wait_duration_ms, - wt.waiting_task_address - FROM - ( - SELECT TOP(@i) - wt0.wait_type COLLATE Latin1_General_Bin2 AS wait_type, - wt0.resource_description COLLATE Latin1_General_Bin2 AS resource_description, - wt0.wait_duration_ms, - wt0.waiting_task_address, - CASE - WHEN wt0.blocking_session_id = p.blocked THEN - wt0.blocking_session_id - ELSE - NULL - END AS blocking_session_id - FROM sys.dm_os_waiting_tasks AS wt0 - CROSS APPLY - ( - SELECT TOP(1) - s0.blocked - FROM @sessions AS s0 - WHERE - s0.session_id = wt0.session_id - AND COALESCE(s0.wait_type, N'''') <> N''OLEDB'' - AND wt0.wait_type <> N''OLEDB'' - ) AS p - ) AS wt - ) AS wt1 - GROUP BY - wt1.wait_type, - wt1.waiting_task_address - ) AS wt2 ON - wt2.waiting_task_address = task_info.task_address - AND wt2.wait_duration_ms > 0 - AND task_info.runnable_time IS NULL - GROUP BY - task_info.session_id, - task_info.request_id, - task_info.physical_io, - task_info.context_switches, - task_info.thread_CPU_snapshot, - task_info.num_tasks, - CASE - WHEN task_info.runnable_time IS NOT NULL THEN - ''RUNNABLE'' - ELSE - wt2.wait_type - END - ) AS w1 - ) AS waits - ORDER BY - waits.session_id, - waits.request_id, - waits.r - FOR XML - PATH(N''tasks''), - TYPE - ) AS tasks_raw (task_xml_raw) - ) AS tasks_final - CROSS APPLY tasks_final.task_xml.nodes(N''/tasks'') AS task_nodes (task_node) - WHERE - task_nodes.task_node.exist(N''session_id'') = 1 - ) AS tasks ON - tasks.session_id = y.session_id - AND tasks.request_id = y.request_id - ' - ELSE - '' - END + - 'LEFT OUTER HASH JOIN - ( - SELECT TOP(@i) - t_info.session_id, - COALESCE(t_info.request_id, -1) AS request_id, - SUM(t_info.tempdb_allocations) AS tempdb_allocations, - SUM(t_info.tempdb_current) AS tempdb_current - FROM - ( - SELECT TOP(@i) - tsu.session_id, - tsu.request_id, - tsu.user_objects_alloc_page_count + - tsu.internal_objects_alloc_page_count AS tempdb_allocations, - tsu.user_objects_alloc_page_count + - tsu.internal_objects_alloc_page_count - - tsu.user_objects_dealloc_page_count - - tsu.internal_objects_dealloc_page_count AS tempdb_current - FROM sys.dm_db_task_space_usage AS tsu - CROSS APPLY - ( - SELECT TOP(1) - s0.session_id - FROM @sessions AS s0 - WHERE - s0.session_id = tsu.session_id - ) AS p - - UNION ALL - - SELECT TOP(@i) - ssu.session_id, - NULL AS request_id, - ssu.user_objects_alloc_page_count + - ssu.internal_objects_alloc_page_count AS tempdb_allocations, - ssu.user_objects_alloc_page_count + - ssu.internal_objects_alloc_page_count - - ssu.user_objects_dealloc_page_count - - ssu.internal_objects_dealloc_page_count AS tempdb_current - FROM sys.dm_db_session_space_usage AS ssu - CROSS APPLY - ( - SELECT TOP(1) - s0.session_id - FROM @sessions AS s0 - WHERE - s0.session_id = ssu.session_id - ) AS p - ) AS t_info - GROUP BY - t_info.session_id, - COALESCE(t_info.request_id, -1) - ) AS tempdb_info ON - tempdb_info.session_id = y.session_id - AND tempdb_info.request_id = - CASE - WHEN y.status = N''sleeping'' THEN - -1 - ELSE - y.request_id - END - ' + - CASE - WHEN - NOT - ( - @get_avg_time = 1 - AND @recursion = 1 - ) THEN - '' - ELSE - 'LEFT OUTER HASH JOIN - ( - SELECT TOP(@i) - * - FROM sys.dm_exec_query_stats - ) AS qs ON - qs.sql_handle = y.sql_handle - AND qs.plan_handle = y.plan_handle - AND qs.statement_start_offset = y.statement_start_offset - AND qs.statement_end_offset = y.statement_end_offset - ' - END + - ') AS x - OPTION (KEEPFIXED PLAN, OPTIMIZE FOR (@i = 1)); '; - - SET @sql_n = CONVERT(NVARCHAR(MAX), @sql); - - SET @last_collection_start = GETDATE(); - - IF @recursion = -1 - BEGIN; - SELECT - @first_collection_ms_ticks = ms_ticks - FROM sys.dm_os_sys_info; - END; - - INSERT #sessions - ( - recursion, - session_id, - request_id, - session_number, - elapsed_time, - avg_elapsed_time, - physical_io, - reads, - physical_reads, - writes, - tempdb_allocations, - tempdb_current, - CPU, - thread_CPU_snapshot, - context_switches, - used_memory, - tasks, - status, - wait_info, - transaction_id, - open_tran_count, - sql_handle, - statement_start_offset, - statement_end_offset, - sql_text, - plan_handle, - blocking_session_id, - percent_complete, - host_name, - login_name, - database_name, - program_name, - additional_info, - start_time, - login_time, - last_request_start_time - ) - EXEC sp_executesql - @sql_n, - N'@recursion SMALLINT, @filter sysname, @not_filter sysname, @first_collection_ms_ticks BIGINT', - @recursion, @filter, @not_filter, @first_collection_ms_ticks; - - --Collect transaction information? - IF - @recursion = 1 - AND - ( - @output_column_list LIKE '%|[tran_start_time|]%' ESCAPE '|' - OR @output_column_list LIKE '%|[tran_log_writes|]%' ESCAPE '|' - ) - BEGIN; - DECLARE @i INT; - SET @i = 2147483647; - - UPDATE s - SET - tran_start_time = - CONVERT - ( - DATETIME, - LEFT - ( - x.trans_info, - NULLIF(CHARINDEX(NCHAR(254) COLLATE Latin1_General_Bin2, x.trans_info) - 1, -1) - ), - 121 - ), - tran_log_writes = - RIGHT - ( - x.trans_info, - LEN(x.trans_info) - CHARINDEX(NCHAR(254) COLLATE Latin1_General_Bin2, x.trans_info) - ) - FROM - ( - SELECT TOP(@i) - trans_nodes.trans_node.value('(session_id/text())[1]', 'SMALLINT') AS session_id, - COALESCE(trans_nodes.trans_node.value('(request_id/text())[1]', 'INT'), 0) AS request_id, - trans_nodes.trans_node.value('(trans_info/text())[1]', 'NVARCHAR(4000)') AS trans_info - FROM - ( - SELECT TOP(@i) - CONVERT - ( - XML, - REPLACE - ( - CONVERT(NVARCHAR(MAX), trans_raw.trans_xml_raw) COLLATE Latin1_General_Bin2, - N'', N'' - ) - ) - FROM - ( - SELECT TOP(@i) - CASE u_trans.r - WHEN 1 THEN u_trans.session_id - ELSE NULL - END AS [session_id], - CASE u_trans.r - WHEN 1 THEN u_trans.request_id - ELSE NULL - END AS [request_id], - CONVERT - ( - NVARCHAR(MAX), - CASE - WHEN u_trans.database_id IS NOT NULL THEN - CASE u_trans.r - WHEN 1 THEN COALESCE(CONVERT(NVARCHAR, u_trans.transaction_start_time, 121) + NCHAR(254), N'') - ELSE N'' - END + - REPLACE - ( - REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE( - REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE( - REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE( - CONVERT(VARCHAR(128), COALESCE(DB_NAME(u_trans.database_id), N'(null)')), - NCHAR(31),N'?'),NCHAR(30),N'?'),NCHAR(29),N'?'),NCHAR(28),N'?'),NCHAR(27),N'?'),NCHAR(26),N'?'),NCHAR(25),N'?'),NCHAR(24),N'?'),NCHAR(23),N'?'),NCHAR(22),N'?'), - NCHAR(21),N'?'),NCHAR(20),N'?'),NCHAR(19),N'?'),NCHAR(18),N'?'),NCHAR(17),N'?'),NCHAR(16),N'?'),NCHAR(15),N'?'),NCHAR(14),N'?'),NCHAR(12),N'?'), - NCHAR(11),N'?'),NCHAR(8),N'?'),NCHAR(7),N'?'),NCHAR(6),N'?'),NCHAR(5),N'?'),NCHAR(4),N'?'),NCHAR(3),N'?'),NCHAR(2),N'?'),NCHAR(1),N'?'), - NCHAR(0), - N'?' - ) + - N': ' + - CONVERT(NVARCHAR, u_trans.log_record_count) + N' (' + CONVERT(NVARCHAR, u_trans.log_kb_used) + N' kB)' + - N',' - ELSE - N'N/A,' - END COLLATE Latin1_General_Bin2 - ) AS [trans_info] - FROM - ( - SELECT TOP(@i) - trans.*, - ROW_NUMBER() OVER - ( - PARTITION BY - trans.session_id, - trans.request_id - ORDER BY - trans.transaction_start_time DESC - ) AS r - FROM - ( - SELECT TOP(@i) - session_tran_map.session_id, - session_tran_map.request_id, - s_tran.database_id, - COALESCE(SUM(s_tran.database_transaction_log_record_count), 0) AS log_record_count, - COALESCE(SUM(s_tran.database_transaction_log_bytes_used), 0) / 1024 AS log_kb_used, - MIN(s_tran.database_transaction_begin_time) AS transaction_start_time - FROM - ( - SELECT TOP(@i) - * - FROM sys.dm_tran_active_transactions - WHERE - transaction_begin_time <= @last_collection_start - ) AS a_tran - INNER HASH JOIN - ( - SELECT TOP(@i) - * - FROM sys.dm_tran_database_transactions - WHERE - database_id < 32767 - ) AS s_tran ON - s_tran.transaction_id = a_tran.transaction_id - LEFT OUTER HASH JOIN - ( - SELECT TOP(@i) - * - FROM sys.dm_tran_session_transactions - ) AS tst ON - s_tran.transaction_id = tst.transaction_id - CROSS APPLY - ( - SELECT TOP(1) - s3.session_id, - s3.request_id - FROM - ( - SELECT TOP(1) - s1.session_id, - s1.request_id - FROM #sessions AS s1 - WHERE - s1.transaction_id = s_tran.transaction_id - AND s1.recursion = 1 - - UNION ALL - - SELECT TOP(1) - s2.session_id, - s2.request_id - FROM #sessions AS s2 - WHERE - s2.session_id = tst.session_id - AND s2.recursion = 1 - ) AS s3 - ORDER BY - s3.request_id - ) AS session_tran_map - GROUP BY - session_tran_map.session_id, - session_tran_map.request_id, - s_tran.database_id - ) AS trans - ) AS u_trans - FOR XML - PATH('trans'), - TYPE - ) AS trans_raw (trans_xml_raw) - ) AS trans_final (trans_xml) - CROSS APPLY trans_final.trans_xml.nodes('/trans') AS trans_nodes (trans_node) - ) AS x - INNER HASH JOIN #sessions AS s ON - s.session_id = x.session_id - AND s.request_id = x.request_id - OPTION (OPTIMIZE FOR (@i = 1)); - END; - - --Variables for text and plan collection - DECLARE - @session_id SMALLINT, - @request_id INT, - @sql_handle VARBINARY(64), - @plan_handle VARBINARY(64), - @statement_start_offset INT, - @statement_end_offset INT, - @start_time DATETIME, - @database_name sysname; - - IF - @recursion = 1 - AND @output_column_list LIKE '%|[sql_text|]%' ESCAPE '|' - BEGIN; - DECLARE sql_cursor - CURSOR LOCAL FAST_FORWARD - FOR - SELECT - session_id, - request_id, - sql_handle, - statement_start_offset, - statement_end_offset - FROM #sessions - WHERE - recursion = 1 - AND sql_handle IS NOT NULL - OPTION (KEEPFIXED PLAN); - - OPEN sql_cursor; - - FETCH NEXT FROM sql_cursor - INTO - @session_id, - @request_id, - @sql_handle, - @statement_start_offset, - @statement_end_offset; - - --Wait up to 5 ms for the SQL text, then give up - SET LOCK_TIMEOUT 5; - - WHILE @@FETCH_STATUS = 0 - BEGIN; - BEGIN TRY; - UPDATE s - SET - s.sql_text = - ( - SELECT - REPLACE - ( - REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE( - REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE( - REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE( - N'--' + NCHAR(13) + NCHAR(10) + - CASE - WHEN @get_full_inner_text = 1 THEN est.text - WHEN LEN(est.text) < (@statement_end_offset / 2) + 1 THEN est.text - WHEN SUBSTRING(est.text, (@statement_start_offset/2), 2) LIKE N'[a-zA-Z0-9][a-zA-Z0-9]' THEN est.text - ELSE - CASE - WHEN @statement_start_offset > 0 THEN - SUBSTRING - ( - est.text, - ((@statement_start_offset/2) + 1), - ( - CASE - WHEN @statement_end_offset = -1 THEN 2147483647 - ELSE ((@statement_end_offset - @statement_start_offset)/2) + 1 - END - ) - ) - ELSE RTRIM(LTRIM(est.text)) - END - END + - NCHAR(13) + NCHAR(10) + N'--' COLLATE Latin1_General_Bin2, - NCHAR(31),N'?'),NCHAR(30),N'?'),NCHAR(29),N'?'),NCHAR(28),N'?'),NCHAR(27),N'?'),NCHAR(26),N'?'),NCHAR(25),N'?'),NCHAR(24),N'?'),NCHAR(23),N'?'),NCHAR(22),N'?'), - NCHAR(21),N'?'),NCHAR(20),N'?'),NCHAR(19),N'?'),NCHAR(18),N'?'),NCHAR(17),N'?'),NCHAR(16),N'?'),NCHAR(15),N'?'),NCHAR(14),N'?'),NCHAR(12),N'?'), - NCHAR(11),N'?'),NCHAR(8),N'?'),NCHAR(7),N'?'),NCHAR(6),N'?'),NCHAR(5),N'?'),NCHAR(4),N'?'),NCHAR(3),N'?'),NCHAR(2),N'?'),NCHAR(1),N'?'), - NCHAR(0), - N'' - ) AS [processing-instruction(query)] - FOR XML - PATH(''), - TYPE - ), - s.statement_start_offset = - CASE - WHEN LEN(est.text) < (@statement_end_offset / 2) + 1 THEN 0 - WHEN SUBSTRING(CONVERT(VARCHAR(MAX), est.text), (@statement_start_offset/2), 2) LIKE '[a-zA-Z0-9][a-zA-Z0-9]' THEN 0 - ELSE @statement_start_offset - END, - s.statement_end_offset = - CASE - WHEN LEN(est.text) < (@statement_end_offset / 2) + 1 THEN -1 - WHEN SUBSTRING(CONVERT(VARCHAR(MAX), est.text), (@statement_start_offset/2), 2) LIKE '[a-zA-Z0-9][a-zA-Z0-9]' THEN -1 - ELSE @statement_end_offset - END - FROM - #sessions AS s, - ( - SELECT TOP(1) - text - FROM - ( - SELECT - text, - 0 AS row_num - FROM sys.dm_exec_sql_text(@sql_handle) - - UNION ALL - - SELECT - NULL, - 1 AS row_num - ) AS est0 - ORDER BY - row_num - ) AS est - WHERE - s.session_id = @session_id - AND s.request_id = @request_id - AND s.recursion = 1 - OPTION (KEEPFIXED PLAN); - END TRY - BEGIN CATCH; - UPDATE s - SET - s.sql_text = - CASE ERROR_NUMBER() - WHEN 1222 THEN '' - ELSE '' - END - FROM #sessions AS s - WHERE - s.session_id = @session_id - AND s.request_id = @request_id - AND s.recursion = 1 - OPTION (KEEPFIXED PLAN); - END CATCH; - - FETCH NEXT FROM sql_cursor - INTO - @session_id, - @request_id, - @sql_handle, - @statement_start_offset, - @statement_end_offset; - END; - - --Return this to the default - SET LOCK_TIMEOUT -1; - - CLOSE sql_cursor; - DEALLOCATE sql_cursor; - END; - - IF - @get_outer_command = 1 - AND @recursion = 1 - AND @output_column_list LIKE '%|[sql_command|]%' ESCAPE '|' - BEGIN; - DECLARE @buffer_results TABLE - ( - EventType VARCHAR(30), - Parameters INT, - EventInfo NVARCHAR(4000), - start_time DATETIME, - session_number INT IDENTITY(1,1) NOT NULL PRIMARY KEY - ); - - DECLARE buffer_cursor - CURSOR LOCAL FAST_FORWARD - FOR - SELECT - session_id, - MAX(start_time) AS start_time - FROM #sessions - WHERE - recursion = 1 - GROUP BY - session_id - ORDER BY - session_id - OPTION (KEEPFIXED PLAN); - - OPEN buffer_cursor; - - FETCH NEXT FROM buffer_cursor - INTO - @session_id, - @start_time; - - WHILE @@FETCH_STATUS = 0 - BEGIN; - BEGIN TRY; - --In SQL Server 2008, DBCC INPUTBUFFER will throw - --an exception if the session no longer exists - INSERT @buffer_results - ( - EventType, - Parameters, - EventInfo - ) - EXEC sp_executesql - N'DBCC INPUTBUFFER(@session_id) WITH NO_INFOMSGS;', - N'@session_id SMALLINT', - @session_id; - - UPDATE br - SET - br.start_time = @start_time - FROM @buffer_results AS br - WHERE - br.session_number = - ( - SELECT MAX(br2.session_number) - FROM @buffer_results br2 - ); - END TRY - BEGIN CATCH - END CATCH; - - FETCH NEXT FROM buffer_cursor - INTO - @session_id, - @start_time; - END; - - UPDATE s - SET - sql_command = - ( - SELECT - REPLACE - ( - REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE( - REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE( - REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE( - CONVERT - ( - NVARCHAR(MAX), - N'--' + NCHAR(13) + NCHAR(10) + br.EventInfo + NCHAR(13) + NCHAR(10) + N'--' COLLATE Latin1_General_Bin2 - ), - NCHAR(31),N'?'),NCHAR(30),N'?'),NCHAR(29),N'?'),NCHAR(28),N'?'),NCHAR(27),N'?'),NCHAR(26),N'?'),NCHAR(25),N'?'),NCHAR(24),N'?'),NCHAR(23),N'?'),NCHAR(22),N'?'), - NCHAR(21),N'?'),NCHAR(20),N'?'),NCHAR(19),N'?'),NCHAR(18),N'?'),NCHAR(17),N'?'),NCHAR(16),N'?'),NCHAR(15),N'?'),NCHAR(14),N'?'),NCHAR(12),N'?'), - NCHAR(11),N'?'),NCHAR(8),N'?'),NCHAR(7),N'?'),NCHAR(6),N'?'),NCHAR(5),N'?'),NCHAR(4),N'?'),NCHAR(3),N'?'),NCHAR(2),N'?'),NCHAR(1),N'?'), - NCHAR(0), - N'' - ) AS [processing-instruction(query)] - FROM @buffer_results AS br - WHERE - br.session_number = s.session_number - AND br.start_time = s.start_time - AND - ( - ( - s.start_time = s.last_request_start_time - AND EXISTS - ( - SELECT * - FROM sys.dm_exec_requests r2 - WHERE - r2.session_id = s.session_id - AND r2.request_id = s.request_id - AND r2.start_time = s.start_time - ) - ) - OR - ( - s.request_id = 0 - AND EXISTS - ( - SELECT * - FROM sys.dm_exec_sessions s2 - WHERE - s2.session_id = s.session_id - AND s2.last_request_start_time = s.last_request_start_time - ) - ) - ) - FOR XML - PATH(''), - TYPE - ) - FROM #sessions AS s - WHERE - recursion = 1 - OPTION (KEEPFIXED PLAN); - - CLOSE buffer_cursor; - DEALLOCATE buffer_cursor; - END; - - IF - @get_plans >= 1 - AND @recursion = 1 - AND @output_column_list LIKE '%|[query_plan|]%' ESCAPE '|' - BEGIN; - DECLARE plan_cursor - CURSOR LOCAL FAST_FORWARD - FOR - SELECT - session_id, - request_id, - plan_handle, - statement_start_offset, - statement_end_offset - FROM #sessions - WHERE - recursion = 1 - AND plan_handle IS NOT NULL - OPTION (KEEPFIXED PLAN); - - OPEN plan_cursor; - - FETCH NEXT FROM plan_cursor - INTO - @session_id, - @request_id, - @plan_handle, - @statement_start_offset, - @statement_end_offset; - - --Wait up to 5 ms for a query plan, then give up - SET LOCK_TIMEOUT 5; - - WHILE @@FETCH_STATUS = 0 - BEGIN; - BEGIN TRY; - UPDATE s - SET - s.query_plan = - ( - SELECT - CONVERT(xml, query_plan) - FROM sys.dm_exec_text_query_plan - ( - @plan_handle, - CASE @get_plans - WHEN 1 THEN - @statement_start_offset - ELSE - 0 - END, - CASE @get_plans - WHEN 1 THEN - @statement_end_offset - ELSE - -1 - END - ) - ) - FROM #sessions AS s - WHERE - s.session_id = @session_id - AND s.request_id = @request_id - AND s.recursion = 1 - OPTION (KEEPFIXED PLAN); - END TRY - BEGIN CATCH; - IF ERROR_NUMBER() = 6335 - BEGIN; - UPDATE s - SET - s.query_plan = - ( - SELECT - N'--' + NCHAR(13) + NCHAR(10) + - N'-- Could not render showplan due to XML data type limitations. ' + NCHAR(13) + NCHAR(10) + - N'-- To see the graphical plan save the XML below as a .SQLPLAN file and re-open in SSMS.' + NCHAR(13) + NCHAR(10) + - N'--' + NCHAR(13) + NCHAR(10) + - REPLACE(qp.query_plan, N'' - ELSE '' - END - FROM #sessions AS s - WHERE - s.session_id = @session_id - AND s.request_id = @request_id - AND s.recursion = 1 - OPTION (KEEPFIXED PLAN); - END; - END CATCH; - - FETCH NEXT FROM plan_cursor - INTO - @session_id, - @request_id, - @plan_handle, - @statement_start_offset, - @statement_end_offset; - END; - - --Return this to the default - SET LOCK_TIMEOUT -1; - - CLOSE plan_cursor; - DEALLOCATE plan_cursor; - END; - - IF - @get_locks = 1 - AND @recursion = 1 - AND @output_column_list LIKE '%|[locks|]%' ESCAPE '|' - BEGIN; - DECLARE locks_cursor - CURSOR LOCAL FAST_FORWARD - FOR - SELECT DISTINCT - database_name - FROM #locks - WHERE - EXISTS - ( - SELECT * - FROM #sessions AS s - WHERE - s.session_id = #locks.session_id - AND recursion = 1 - ) - AND database_name <> '(null)' - OPTION (KEEPFIXED PLAN); - - OPEN locks_cursor; - - FETCH NEXT FROM locks_cursor - INTO - @database_name; - - WHILE @@FETCH_STATUS = 0 - BEGIN; - BEGIN TRY; - SET @sql_n = CONVERT(NVARCHAR(MAX), '') + - 'UPDATE l ' + - 'SET ' + - 'object_name = ' + - 'REPLACE ' + - '( ' + - 'REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE( ' + - 'REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE( ' + - 'REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE( ' + - 'o.name COLLATE Latin1_General_Bin2, ' + - 'NCHAR(31),N''?''),NCHAR(30),N''?''),NCHAR(29),N''?''),NCHAR(28),N''?''),NCHAR(27),N''?''),NCHAR(26),N''?''),NCHAR(25),N''?''),NCHAR(24),N''?''),NCHAR(23),N''?''),NCHAR(22),N''?''), ' + - 'NCHAR(21),N''?''),NCHAR(20),N''?''),NCHAR(19),N''?''),NCHAR(18),N''?''),NCHAR(17),N''?''),NCHAR(16),N''?''),NCHAR(15),N''?''),NCHAR(14),N''?''),NCHAR(12),N''?''), ' + - 'NCHAR(11),N''?''),NCHAR(8),N''?''),NCHAR(7),N''?''),NCHAR(6),N''?''),NCHAR(5),N''?''),NCHAR(4),N''?''),NCHAR(3),N''?''),NCHAR(2),N''?''),NCHAR(1),N''?''), ' + - 'NCHAR(0), ' + - N''''' ' + - '), ' + - 'index_name = ' + - 'REPLACE ' + - '( ' + - 'REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE( ' + - 'REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE( ' + - 'REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE( ' + - 'i.name COLLATE Latin1_General_Bin2, ' + - 'NCHAR(31),N''?''),NCHAR(30),N''?''),NCHAR(29),N''?''),NCHAR(28),N''?''),NCHAR(27),N''?''),NCHAR(26),N''?''),NCHAR(25),N''?''),NCHAR(24),N''?''),NCHAR(23),N''?''),NCHAR(22),N''?''), ' + - 'NCHAR(21),N''?''),NCHAR(20),N''?''),NCHAR(19),N''?''),NCHAR(18),N''?''),NCHAR(17),N''?''),NCHAR(16),N''?''),NCHAR(15),N''?''),NCHAR(14),N''?''),NCHAR(12),N''?''), ' + - 'NCHAR(11),N''?''),NCHAR(8),N''?''),NCHAR(7),N''?''),NCHAR(6),N''?''),NCHAR(5),N''?''),NCHAR(4),N''?''),NCHAR(3),N''?''),NCHAR(2),N''?''),NCHAR(1),N''?''), ' + - 'NCHAR(0), ' + - N''''' ' + - '), ' + - 'schema_name = ' + - 'REPLACE ' + - '( ' + - 'REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE( ' + - 'REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE( ' + - 'REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE( ' + - 's.name COLLATE Latin1_General_Bin2, ' + - 'NCHAR(31),N''?''),NCHAR(30),N''?''),NCHAR(29),N''?''),NCHAR(28),N''?''),NCHAR(27),N''?''),NCHAR(26),N''?''),NCHAR(25),N''?''),NCHAR(24),N''?''),NCHAR(23),N''?''),NCHAR(22),N''?''), ' + - 'NCHAR(21),N''?''),NCHAR(20),N''?''),NCHAR(19),N''?''),NCHAR(18),N''?''),NCHAR(17),N''?''),NCHAR(16),N''?''),NCHAR(15),N''?''),NCHAR(14),N''?''),NCHAR(12),N''?''), ' + - 'NCHAR(11),N''?''),NCHAR(8),N''?''),NCHAR(7),N''?''),NCHAR(6),N''?''),NCHAR(5),N''?''),NCHAR(4),N''?''),NCHAR(3),N''?''),NCHAR(2),N''?''),NCHAR(1),N''?''), ' + - 'NCHAR(0), ' + - N''''' ' + - '), ' + - 'principal_name = ' + - 'REPLACE ' + - '( ' + - 'REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE( ' + - 'REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE( ' + - 'REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE( ' + - 'dp.name COLLATE Latin1_General_Bin2, ' + - 'NCHAR(31),N''?''),NCHAR(30),N''?''),NCHAR(29),N''?''),NCHAR(28),N''?''),NCHAR(27),N''?''),NCHAR(26),N''?''),NCHAR(25),N''?''),NCHAR(24),N''?''),NCHAR(23),N''?''),NCHAR(22),N''?''), ' + - 'NCHAR(21),N''?''),NCHAR(20),N''?''),NCHAR(19),N''?''),NCHAR(18),N''?''),NCHAR(17),N''?''),NCHAR(16),N''?''),NCHAR(15),N''?''),NCHAR(14),N''?''),NCHAR(12),N''?''), ' + - 'NCHAR(11),N''?''),NCHAR(8),N''?''),NCHAR(7),N''?''),NCHAR(6),N''?''),NCHAR(5),N''?''),NCHAR(4),N''?''),NCHAR(3),N''?''),NCHAR(2),N''?''),NCHAR(1),N''?''), ' + - 'NCHAR(0), ' + - N''''' ' + - ') ' + - 'FROM #locks AS l ' + - 'LEFT OUTER JOIN ' + QUOTENAME(@database_name) + '.sys.allocation_units AS au ON ' + - 'au.allocation_unit_id = l.allocation_unit_id ' + - 'LEFT OUTER JOIN ' + QUOTENAME(@database_name) + '.sys.partitions AS p ON ' + - 'p.hobt_id = ' + - 'COALESCE ' + - '( ' + - 'l.hobt_id, ' + - 'CASE ' + - 'WHEN au.type IN (1, 3) THEN au.container_id ' + - 'ELSE NULL ' + - 'END ' + - ') ' + - 'LEFT OUTER JOIN ' + QUOTENAME(@database_name) + '.sys.partitions AS p1 ON ' + - 'l.hobt_id IS NULL ' + - 'AND au.type = 2 ' + - 'AND p1.partition_id = au.container_id ' + - 'LEFT OUTER JOIN ' + QUOTENAME(@database_name) + '.sys.objects AS o ON ' + - 'o.object_id = COALESCE(l.object_id, p.object_id, p1.object_id) ' + - 'LEFT OUTER JOIN ' + QUOTENAME(@database_name) + '.sys.indexes AS i ON ' + - 'i.object_id = COALESCE(l.object_id, p.object_id, p1.object_id) ' + - 'AND i.index_id = COALESCE(l.index_id, p.index_id, p1.index_id) ' + - 'LEFT OUTER JOIN ' + QUOTENAME(@database_name) + '.sys.schemas AS s ON ' + - 's.schema_id = COALESCE(l.schema_id, o.schema_id) ' + - 'LEFT OUTER JOIN ' + QUOTENAME(@database_name) + '.sys.database_principals AS dp ON ' + - 'dp.principal_id = l.principal_id ' + - 'WHERE ' + - 'l.database_name = @database_name ' + - 'OPTION (KEEPFIXED PLAN); '; - - EXEC sp_executesql - @sql_n, - N'@database_name sysname', - @database_name; - END TRY - BEGIN CATCH; - UPDATE #locks - SET - query_error = - REPLACE - ( - REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE( - REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE( - REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE( - CONVERT - ( - NVARCHAR(MAX), - ERROR_MESSAGE() COLLATE Latin1_General_Bin2 - ), - NCHAR(31),N'?'),NCHAR(30),N'?'),NCHAR(29),N'?'),NCHAR(28),N'?'),NCHAR(27),N'?'),NCHAR(26),N'?'),NCHAR(25),N'?'),NCHAR(24),N'?'),NCHAR(23),N'?'),NCHAR(22),N'?'), - NCHAR(21),N'?'),NCHAR(20),N'?'),NCHAR(19),N'?'),NCHAR(18),N'?'),NCHAR(17),N'?'),NCHAR(16),N'?'),NCHAR(15),N'?'),NCHAR(14),N'?'),NCHAR(12),N'?'), - NCHAR(11),N'?'),NCHAR(8),N'?'),NCHAR(7),N'?'),NCHAR(6),N'?'),NCHAR(5),N'?'),NCHAR(4),N'?'),NCHAR(3),N'?'),NCHAR(2),N'?'),NCHAR(1),N'?'), - NCHAR(0), - N'' - ) - WHERE - database_name = @database_name - OPTION (KEEPFIXED PLAN); - END CATCH; - - FETCH NEXT FROM locks_cursor - INTO - @database_name; - END; - - CLOSE locks_cursor; - DEALLOCATE locks_cursor; - - CREATE CLUSTERED INDEX IX_SRD ON #locks (session_id, request_id, database_name); - - UPDATE s - SET - s.locks = - ( - SELECT - REPLACE - ( - REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE( - REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE( - REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE( - CONVERT - ( - NVARCHAR(MAX), - l1.database_name COLLATE Latin1_General_Bin2 - ), - NCHAR(31),N'?'),NCHAR(30),N'?'),NCHAR(29),N'?'),NCHAR(28),N'?'),NCHAR(27),N'?'),NCHAR(26),N'?'),NCHAR(25),N'?'),NCHAR(24),N'?'),NCHAR(23),N'?'),NCHAR(22),N'?'), - NCHAR(21),N'?'),NCHAR(20),N'?'),NCHAR(19),N'?'),NCHAR(18),N'?'),NCHAR(17),N'?'),NCHAR(16),N'?'),NCHAR(15),N'?'),NCHAR(14),N'?'),NCHAR(12),N'?'), - NCHAR(11),N'?'),NCHAR(8),N'?'),NCHAR(7),N'?'),NCHAR(6),N'?'),NCHAR(5),N'?'),NCHAR(4),N'?'),NCHAR(3),N'?'),NCHAR(2),N'?'),NCHAR(1),N'?'), - NCHAR(0), - N'' - ) AS [Database/@name], - MIN(l1.query_error) AS [Database/@query_error], - ( - SELECT - l2.request_mode AS [Lock/@request_mode], - l2.request_status AS [Lock/@request_status], - COUNT(*) AS [Lock/@request_count] - FROM #locks AS l2 - WHERE - l1.session_id = l2.session_id - AND l1.request_id = l2.request_id - AND l2.database_name = l1.database_name - AND l2.resource_type = 'DATABASE' - GROUP BY - l2.request_mode, - l2.request_status - FOR XML - PATH(''), - TYPE - ) AS [Database/Locks], - ( - SELECT - COALESCE(l3.object_name, '(null)') AS [Object/@name], - l3.schema_name AS [Object/@schema_name], - ( - SELECT - l4.resource_type AS [Lock/@resource_type], - l4.page_type AS [Lock/@page_type], - l4.index_name AS [Lock/@index_name], - CASE - WHEN l4.object_name IS NULL THEN l4.schema_name - ELSE NULL - END AS [Lock/@schema_name], - l4.principal_name AS [Lock/@principal_name], - l4.resource_description AS [Lock/@resource_description], - l4.request_mode AS [Lock/@request_mode], - l4.request_status AS [Lock/@request_status], - SUM(l4.request_count) AS [Lock/@request_count] - FROM #locks AS l4 - WHERE - l4.session_id = l3.session_id - AND l4.request_id = l3.request_id - AND l3.database_name = l4.database_name - AND COALESCE(l3.object_name, '(null)') = COALESCE(l4.object_name, '(null)') - AND COALESCE(l3.schema_name, '') = COALESCE(l4.schema_name, '') - AND l4.resource_type <> 'DATABASE' - GROUP BY - l4.resource_type, - l4.page_type, - l4.index_name, - CASE - WHEN l4.object_name IS NULL THEN l4.schema_name - ELSE NULL - END, - l4.principal_name, - l4.resource_description, - l4.request_mode, - l4.request_status - FOR XML - PATH(''), - TYPE - ) AS [Object/Locks] - FROM #locks AS l3 - WHERE - l3.session_id = l1.session_id - AND l3.request_id = l1.request_id - AND l3.database_name = l1.database_name - AND l3.resource_type <> 'DATABASE' - GROUP BY - l3.session_id, - l3.request_id, - l3.database_name, - COALESCE(l3.object_name, '(null)'), - l3.schema_name - FOR XML - PATH(''), - TYPE - ) AS [Database/Objects] - FROM #locks AS l1 - WHERE - l1.session_id = s.session_id - AND l1.request_id = s.request_id - AND l1.start_time IN (s.start_time, s.last_request_start_time) - AND s.recursion = 1 - GROUP BY - l1.session_id, - l1.request_id, - l1.database_name - FOR XML - PATH(''), - TYPE - ) - FROM #sessions s - OPTION (KEEPFIXED PLAN); - END; - - IF - @find_block_leaders = 1 - AND @recursion = 1 - AND @output_column_list LIKE '%|[blocked_session_count|]%' ESCAPE '|' - BEGIN; - WITH - blockers AS - ( - SELECT - session_id, - session_id AS top_level_session_id, - CONVERT(VARCHAR(8000), '.' + CONVERT(VARCHAR(8000), session_id) + '.') AS the_path - FROM #sessions - WHERE - recursion = 1 - - UNION ALL - - SELECT - s.session_id, - b.top_level_session_id, - CONVERT(VARCHAR(8000), b.the_path + CONVERT(VARCHAR(8000), s.session_id) + '.') AS the_path - FROM blockers AS b - JOIN #sessions AS s ON - s.blocking_session_id = b.session_id - AND s.recursion = 1 - AND b.the_path NOT LIKE '%.' + CONVERT(VARCHAR(8000), s.session_id) + '.%' COLLATE Latin1_General_Bin2 - ) - UPDATE s - SET - s.blocked_session_count = x.blocked_session_count - FROM #sessions AS s - JOIN - ( - SELECT - b.top_level_session_id AS session_id, - COUNT(*) - 1 AS blocked_session_count - FROM blockers AS b - GROUP BY - b.top_level_session_id - ) x ON - s.session_id = x.session_id - WHERE - s.recursion = 1; - END; - - IF - @get_task_info = 2 - AND @output_column_list LIKE '%|[additional_info|]%' ESCAPE '|' - AND @recursion = 1 - BEGIN; - CREATE TABLE #blocked_requests - ( - session_id SMALLINT NOT NULL, - request_id INT NOT NULL, - database_name sysname NOT NULL, - object_id INT, - hobt_id BIGINT, - schema_id INT, - schema_name sysname NULL, - object_name sysname NULL, - query_error NVARCHAR(2048), - PRIMARY KEY (database_name, session_id, request_id) - ); - - CREATE STATISTICS s_database_name ON #blocked_requests (database_name) - WITH SAMPLE 0 ROWS, NORECOMPUTE; - CREATE STATISTICS s_schema_name ON #blocked_requests (schema_name) - WITH SAMPLE 0 ROWS, NORECOMPUTE; - CREATE STATISTICS s_object_name ON #blocked_requests (object_name) - WITH SAMPLE 0 ROWS, NORECOMPUTE; - CREATE STATISTICS s_query_error ON #blocked_requests (query_error) - WITH SAMPLE 0 ROWS, NORECOMPUTE; - - INSERT #blocked_requests - ( - session_id, - request_id, - database_name, - object_id, - hobt_id, - schema_id - ) - SELECT - session_id, - request_id, - database_name, - object_id, - hobt_id, - CONVERT(INT, SUBSTRING(schema_node, CHARINDEX(' = ', schema_node) + 3, LEN(schema_node))) AS schema_id - FROM - ( - SELECT - session_id, - request_id, - agent_nodes.agent_node.value('(database_name/text())[1]', 'sysname') AS database_name, - agent_nodes.agent_node.value('(object_id/text())[1]', 'int') AS object_id, - agent_nodes.agent_node.value('(hobt_id/text())[1]', 'bigint') AS hobt_id, - agent_nodes.agent_node.value('(metadata_resource/text()[.="SCHEMA"]/../../metadata_class_id/text())[1]', 'varchar(100)') AS schema_node - FROM #sessions AS s - CROSS APPLY s.additional_info.nodes('//block_info') AS agent_nodes (agent_node) - WHERE - s.recursion = 1 - ) AS t - WHERE - t.database_name IS NOT NULL - AND - ( - t.object_id IS NOT NULL - OR t.hobt_id IS NOT NULL - OR t.schema_node IS NOT NULL - ); - - DECLARE blocks_cursor - CURSOR LOCAL FAST_FORWARD - FOR - SELECT DISTINCT - database_name - FROM #blocked_requests; - - OPEN blocks_cursor; - - FETCH NEXT FROM blocks_cursor - INTO - @database_name; - - WHILE @@FETCH_STATUS = 0 - BEGIN; - BEGIN TRY; - SET @sql_n = - CONVERT(NVARCHAR(MAX), '') + - 'UPDATE b ' + - 'SET ' + - 'b.schema_name = ' + - 'REPLACE ' + - '( ' + - 'REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE( ' + - 'REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE( ' + - 'REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE( ' + - 's.name COLLATE Latin1_General_Bin2, ' + - 'NCHAR(31),N''?''),NCHAR(30),N''?''),NCHAR(29),N''?''),NCHAR(28),N''?''),NCHAR(27),N''?''),NCHAR(26),N''?''),NCHAR(25),N''?''),NCHAR(24),N''?''),NCHAR(23),N''?''),NCHAR(22),N''?''), ' + - 'NCHAR(21),N''?''),NCHAR(20),N''?''),NCHAR(19),N''?''),NCHAR(18),N''?''),NCHAR(17),N''?''),NCHAR(16),N''?''),NCHAR(15),N''?''),NCHAR(14),N''?''),NCHAR(12),N''?''), ' + - 'NCHAR(11),N''?''),NCHAR(8),N''?''),NCHAR(7),N''?''),NCHAR(6),N''?''),NCHAR(5),N''?''),NCHAR(4),N''?''),NCHAR(3),N''?''),NCHAR(2),N''?''),NCHAR(1),N''?''), ' + - 'NCHAR(0), ' + - N''''' ' + - '), ' + - 'b.object_name = ' + - 'REPLACE ' + - '( ' + - 'REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE( ' + - 'REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE( ' + - 'REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE( ' + - 'o.name COLLATE Latin1_General_Bin2, ' + - 'NCHAR(31),N''?''),NCHAR(30),N''?''),NCHAR(29),N''?''),NCHAR(28),N''?''),NCHAR(27),N''?''),NCHAR(26),N''?''),NCHAR(25),N''?''),NCHAR(24),N''?''),NCHAR(23),N''?''),NCHAR(22),N''?''), ' + - 'NCHAR(21),N''?''),NCHAR(20),N''?''),NCHAR(19),N''?''),NCHAR(18),N''?''),NCHAR(17),N''?''),NCHAR(16),N''?''),NCHAR(15),N''?''),NCHAR(14),N''?''),NCHAR(12),N''?''), ' + - 'NCHAR(11),N''?''),NCHAR(8),N''?''),NCHAR(7),N''?''),NCHAR(6),N''?''),NCHAR(5),N''?''),NCHAR(4),N''?''),NCHAR(3),N''?''),NCHAR(2),N''?''),NCHAR(1),N''?''), ' + - 'NCHAR(0), ' + - N''''' ' + - ') ' + - 'FROM #blocked_requests AS b ' + - 'LEFT OUTER JOIN ' + QUOTENAME(@database_name) + '.sys.partitions AS p ON ' + - 'p.hobt_id = b.hobt_id ' + - 'LEFT OUTER JOIN ' + QUOTENAME(@database_name) + '.sys.objects AS o ON ' + - 'o.object_id = COALESCE(p.object_id, b.object_id) ' + - 'LEFT OUTER JOIN ' + QUOTENAME(@database_name) + '.sys.schemas AS s ON ' + - 's.schema_id = COALESCE(o.schema_id, b.schema_id) ' + - 'WHERE ' + - 'b.database_name = @database_name; '; - - EXEC sp_executesql - @sql_n, - N'@database_name sysname', - @database_name; - END TRY - BEGIN CATCH; - UPDATE #blocked_requests - SET - query_error = - REPLACE - ( - REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE( - REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE( - REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE( - CONVERT - ( - NVARCHAR(MAX), - ERROR_MESSAGE() COLLATE Latin1_General_Bin2 - ), - NCHAR(31),N'?'),NCHAR(30),N'?'),NCHAR(29),N'?'),NCHAR(28),N'?'),NCHAR(27),N'?'),NCHAR(26),N'?'),NCHAR(25),N'?'),NCHAR(24),N'?'),NCHAR(23),N'?'),NCHAR(22),N'?'), - NCHAR(21),N'?'),NCHAR(20),N'?'),NCHAR(19),N'?'),NCHAR(18),N'?'),NCHAR(17),N'?'),NCHAR(16),N'?'),NCHAR(15),N'?'),NCHAR(14),N'?'),NCHAR(12),N'?'), - NCHAR(11),N'?'),NCHAR(8),N'?'),NCHAR(7),N'?'),NCHAR(6),N'?'),NCHAR(5),N'?'),NCHAR(4),N'?'),NCHAR(3),N'?'),NCHAR(2),N'?'),NCHAR(1),N'?'), - NCHAR(0), - N'' - ) - WHERE - database_name = @database_name; - END CATCH; - - FETCH NEXT FROM blocks_cursor - INTO - @database_name; - END; - - CLOSE blocks_cursor; - DEALLOCATE blocks_cursor; - - UPDATE s - SET - additional_info.modify - (' - insert {sql:column("b.schema_name")} - as last - into (/additional_info/block_info)[1] - ') - FROM #sessions AS s - INNER JOIN #blocked_requests AS b ON - b.session_id = s.session_id - AND b.request_id = s.request_id - AND s.recursion = 1 - WHERE - b.schema_name IS NOT NULL; - - UPDATE s - SET - additional_info.modify - (' - insert {sql:column("b.object_name")} - as last - into (/additional_info/block_info)[1] - ') - FROM #sessions AS s - INNER JOIN #blocked_requests AS b ON - b.session_id = s.session_id - AND b.request_id = s.request_id - AND s.recursion = 1 - WHERE - b.object_name IS NOT NULL; - - UPDATE s - SET - additional_info.modify - (' - insert {sql:column("b.query_error")} - as last - into (/additional_info/block_info)[1] - ') - FROM #sessions AS s - INNER JOIN #blocked_requests AS b ON - b.session_id = s.session_id - AND b.request_id = s.request_id - AND s.recursion = 1 - WHERE - b.query_error IS NOT NULL; - END; - - IF - @output_column_list LIKE '%|[program_name|]%' ESCAPE '|' - AND @output_column_list LIKE '%|[additional_info|]%' ESCAPE '|' - AND @recursion = 1 - BEGIN; - DECLARE @job_id UNIQUEIDENTIFIER; - DECLARE @step_id INT; - - DECLARE agent_cursor - CURSOR LOCAL FAST_FORWARD - FOR - SELECT - s.session_id, - agent_nodes.agent_node.value('(job_id/text())[1]', 'uniqueidentifier') AS job_id, - agent_nodes.agent_node.value('(step_id/text())[1]', 'int') AS step_id - FROM #sessions AS s - CROSS APPLY s.additional_info.nodes('//agent_job_info') AS agent_nodes (agent_node) - WHERE - s.recursion = 1 - OPTION (KEEPFIXED PLAN); - - OPEN agent_cursor; - - FETCH NEXT FROM agent_cursor - INTO - @session_id, - @job_id, - @step_id; - - WHILE @@FETCH_STATUS = 0 - BEGIN; - BEGIN TRY; - DECLARE @job_name sysname; - SET @job_name = NULL; - DECLARE @step_name sysname; - SET @step_name = NULL; - - SELECT - @job_name = - REPLACE - ( - REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE( - REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE( - REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE( - j.name, - NCHAR(31),N'?'),NCHAR(30),N'?'),NCHAR(29),N'?'),NCHAR(28),N'?'),NCHAR(27),N'?'),NCHAR(26),N'?'),NCHAR(25),N'?'),NCHAR(24),N'?'),NCHAR(23),N'?'),NCHAR(22),N'?'), - NCHAR(21),N'?'),NCHAR(20),N'?'),NCHAR(19),N'?'),NCHAR(18),N'?'),NCHAR(17),N'?'),NCHAR(16),N'?'),NCHAR(15),N'?'),NCHAR(14),N'?'),NCHAR(12),N'?'), - NCHAR(11),N'?'),NCHAR(8),N'?'),NCHAR(7),N'?'),NCHAR(6),N'?'),NCHAR(5),N'?'),NCHAR(4),N'?'),NCHAR(3),N'?'),NCHAR(2),N'?'),NCHAR(1),N'?'), - NCHAR(0), - N'?' - ), - @step_name = - REPLACE - ( - REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE( - REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE( - REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE( - s.step_name, - NCHAR(31),N'?'),NCHAR(30),N'?'),NCHAR(29),N'?'),NCHAR(28),N'?'),NCHAR(27),N'?'),NCHAR(26),N'?'),NCHAR(25),N'?'),NCHAR(24),N'?'),NCHAR(23),N'?'),NCHAR(22),N'?'), - NCHAR(21),N'?'),NCHAR(20),N'?'),NCHAR(19),N'?'),NCHAR(18),N'?'),NCHAR(17),N'?'),NCHAR(16),N'?'),NCHAR(15),N'?'),NCHAR(14),N'?'),NCHAR(12),N'?'), - NCHAR(11),N'?'),NCHAR(8),N'?'),NCHAR(7),N'?'),NCHAR(6),N'?'),NCHAR(5),N'?'),NCHAR(4),N'?'),NCHAR(3),N'?'),NCHAR(2),N'?'),NCHAR(1),N'?'), - NCHAR(0), - N'?' - ) - FROM msdb.dbo.sysjobs AS j - INNER JOIN msdb..sysjobsteps AS s ON - j.job_id = s.job_id - WHERE - j.job_id = @job_id - AND s.step_id = @step_id; - - IF @job_name IS NOT NULL - BEGIN; - UPDATE s - SET - additional_info.modify - (' - insert text{sql:variable("@job_name")} - into (/additional_info/agent_job_info/job_name)[1] - ') - FROM #sessions AS s - WHERE - s.session_id = @session_id - OPTION (KEEPFIXED PLAN); - - UPDATE s - SET - additional_info.modify - (' - insert text{sql:variable("@step_name")} - into (/additional_info/agent_job_info/step_name)[1] - ') - FROM #sessions AS s - WHERE - s.session_id = @session_id - OPTION (KEEPFIXED PLAN); - END; - END TRY - BEGIN CATCH; - DECLARE @msdb_error_message NVARCHAR(256); - SET @msdb_error_message = ERROR_MESSAGE(); - - UPDATE s - SET - additional_info.modify - (' - insert {sql:variable("@msdb_error_message")} - as last - into (/additional_info/agent_job_info)[1] - ') - FROM #sessions AS s - WHERE - s.session_id = @session_id - AND s.recursion = 1 - OPTION (KEEPFIXED PLAN); - END CATCH; - - FETCH NEXT FROM agent_cursor - INTO - @session_id, - @job_id, - @step_id; - END; - - CLOSE agent_cursor; - DEALLOCATE agent_cursor; - END; - - IF - @delta_interval > 0 - AND @recursion <> 1 - BEGIN; - SET @recursion = 1; - - DECLARE @delay_time CHAR(12); - SET @delay_time = CONVERT(VARCHAR, DATEADD(second, @delta_interval, 0), 114); - WAITFOR DELAY @delay_time; - - GOTO REDO; - END; - END; - - SET @sql = - --Outer column list - CONVERT - ( - VARCHAR(MAX), - CASE - WHEN - @destination_table <> '' - AND @return_schema = 0 - THEN 'INSERT ' + @destination_table + ' ' - ELSE '' - END + - 'SELECT ' + - @output_column_list + ' ' + - CASE @return_schema - WHEN 1 THEN 'INTO #session_schema ' - ELSE '' - END - --End outer column list - ) + - --Inner column list - CONVERT - ( - VARCHAR(MAX), - 'FROM ' + - '( ' + - 'SELECT ' + - 'session_id, ' + - --[dd hh:mm:ss.mss] - CASE - WHEN @format_output IN (1, 2) THEN - 'CASE ' + - 'WHEN elapsed_time < 0 THEN ' + - 'RIGHT ' + - '( ' + - 'REPLICATE(''0'', max_elapsed_length) + CONVERT(VARCHAR, (-1 * elapsed_time) / 86400), ' + - 'max_elapsed_length ' + - ') + ' + - 'RIGHT ' + - '( ' + - 'CONVERT(VARCHAR, DATEADD(second, (-1 * elapsed_time), 0), 120), ' + - '9 ' + - ') + ' + - '''.000'' ' + - 'ELSE ' + - 'RIGHT ' + - '( ' + - 'REPLICATE(''0'', max_elapsed_length) + CONVERT(VARCHAR, elapsed_time / 86400000), ' + - 'max_elapsed_length ' + - ') + ' + - 'RIGHT ' + - '( ' + - 'CONVERT(VARCHAR, DATEADD(second, elapsed_time / 1000, 0), 120), ' + - '9 ' + - ') + ' + - '''.'' + ' + - 'RIGHT(''000'' + CONVERT(VARCHAR, elapsed_time % 1000), 3) ' + - 'END AS [dd hh:mm:ss.mss], ' - ELSE - '' - END + - --[dd hh:mm:ss.mss (avg)] / avg_elapsed_time - CASE - WHEN @format_output IN (1, 2) THEN - 'RIGHT ' + - '( ' + - '''00'' + CONVERT(VARCHAR, avg_elapsed_time / 86400000), ' + - '2 ' + - ') + ' + - 'RIGHT ' + - '( ' + - 'CONVERT(VARCHAR, DATEADD(second, avg_elapsed_time / 1000, 0), 120), ' + - '9 ' + - ') + ' + - '''.'' + ' + - 'RIGHT(''000'' + CONVERT(VARCHAR, avg_elapsed_time % 1000), 3) AS [dd hh:mm:ss.mss (avg)], ' - ELSE - 'avg_elapsed_time, ' - END + - --physical_io - CASE @format_output - WHEN 1 THEN 'CONVERT(VARCHAR, SPACE(MAX(LEN(CONVERT(VARCHAR, physical_io))) OVER() - LEN(CONVERT(VARCHAR, physical_io))) + LEFT(CONVERT(CHAR(22), CONVERT(MONEY, physical_io), 1), 19)) AS ' - WHEN 2 THEN 'CONVERT(VARCHAR, LEFT(CONVERT(CHAR(22), CONVERT(MONEY, physical_io), 1), 19)) AS ' - ELSE '' - END + 'physical_io, ' + - --reads - CASE @format_output - WHEN 1 THEN 'CONVERT(VARCHAR, SPACE(MAX(LEN(CONVERT(VARCHAR, reads))) OVER() - LEN(CONVERT(VARCHAR, reads))) + LEFT(CONVERT(CHAR(22), CONVERT(MONEY, reads), 1), 19)) AS ' - WHEN 2 THEN 'CONVERT(VARCHAR, LEFT(CONVERT(CHAR(22), CONVERT(MONEY, reads), 1), 19)) AS ' - ELSE '' - END + 'reads, ' + - --physical_reads - CASE @format_output - WHEN 1 THEN 'CONVERT(VARCHAR, SPACE(MAX(LEN(CONVERT(VARCHAR, physical_reads))) OVER() - LEN(CONVERT(VARCHAR, physical_reads))) + LEFT(CONVERT(CHAR(22), CONVERT(MONEY, physical_reads), 1), 19)) AS ' - WHEN 2 THEN 'CONVERT(VARCHAR, LEFT(CONVERT(CHAR(22), CONVERT(MONEY, physical_reads), 1), 19)) AS ' - ELSE '' - END + 'physical_reads, ' + - --writes - CASE @format_output - WHEN 1 THEN 'CONVERT(VARCHAR, SPACE(MAX(LEN(CONVERT(VARCHAR, writes))) OVER() - LEN(CONVERT(VARCHAR, writes))) + LEFT(CONVERT(CHAR(22), CONVERT(MONEY, writes), 1), 19)) AS ' - WHEN 2 THEN 'CONVERT(VARCHAR, LEFT(CONVERT(CHAR(22), CONVERT(MONEY, writes), 1), 19)) AS ' - ELSE '' - END + 'writes, ' + - --tempdb_allocations - CASE @format_output - WHEN 1 THEN 'CONVERT(VARCHAR, SPACE(MAX(LEN(CONVERT(VARCHAR, tempdb_allocations))) OVER() - LEN(CONVERT(VARCHAR, tempdb_allocations))) + LEFT(CONVERT(CHAR(22), CONVERT(MONEY, tempdb_allocations), 1), 19)) AS ' - WHEN 2 THEN 'CONVERT(VARCHAR, LEFT(CONVERT(CHAR(22), CONVERT(MONEY, tempdb_allocations), 1), 19)) AS ' - ELSE '' - END + 'tempdb_allocations, ' + - --tempdb_current - CASE @format_output - WHEN 1 THEN 'CONVERT(VARCHAR, SPACE(MAX(LEN(CONVERT(VARCHAR, tempdb_current))) OVER() - LEN(CONVERT(VARCHAR, tempdb_current))) + LEFT(CONVERT(CHAR(22), CONVERT(MONEY, tempdb_current), 1), 19)) AS ' - WHEN 2 THEN 'CONVERT(VARCHAR, LEFT(CONVERT(CHAR(22), CONVERT(MONEY, tempdb_current), 1), 19)) AS ' - ELSE '' - END + 'tempdb_current, ' + - --CPU - CASE @format_output - WHEN 1 THEN 'CONVERT(VARCHAR, SPACE(MAX(LEN(CONVERT(VARCHAR, CPU))) OVER() - LEN(CONVERT(VARCHAR, CPU))) + LEFT(CONVERT(CHAR(22), CONVERT(MONEY, CPU), 1), 19)) AS ' - WHEN 2 THEN 'CONVERT(VARCHAR, LEFT(CONVERT(CHAR(22), CONVERT(MONEY, CPU), 1), 19)) AS ' - ELSE '' - END + 'CPU, ' + - --context_switches - CASE @format_output - WHEN 1 THEN 'CONVERT(VARCHAR, SPACE(MAX(LEN(CONVERT(VARCHAR, context_switches))) OVER() - LEN(CONVERT(VARCHAR, context_switches))) + LEFT(CONVERT(CHAR(22), CONVERT(MONEY, context_switches), 1), 19)) AS ' - WHEN 2 THEN 'CONVERT(VARCHAR, LEFT(CONVERT(CHAR(22), CONVERT(MONEY, context_switches), 1), 19)) AS ' - ELSE '' - END + 'context_switches, ' + - --used_memory - CASE @format_output - WHEN 1 THEN 'CONVERT(VARCHAR, SPACE(MAX(LEN(CONVERT(VARCHAR, used_memory))) OVER() - LEN(CONVERT(VARCHAR, used_memory))) + LEFT(CONVERT(CHAR(22), CONVERT(MONEY, used_memory), 1), 19)) AS ' - WHEN 2 THEN 'CONVERT(VARCHAR, LEFT(CONVERT(CHAR(22), CONVERT(MONEY, used_memory), 1), 19)) AS ' - ELSE '' - END + 'used_memory, ' + - CASE - WHEN @output_column_list LIKE '%|_delta|]%' ESCAPE '|' THEN - --physical_io_delta - 'CASE ' + - 'WHEN ' + - 'first_request_start_time = last_request_start_time ' + - 'AND num_events = 2 ' + - 'AND physical_io_delta >= 0 ' + - 'THEN ' + - CASE @format_output - WHEN 1 THEN 'CONVERT(VARCHAR, SPACE(MAX(LEN(CONVERT(VARCHAR, physical_io_delta))) OVER() - LEN(CONVERT(VARCHAR, physical_io_delta))) + LEFT(CONVERT(CHAR(22), CONVERT(MONEY, physical_io_delta), 1), 19)) ' - WHEN 2 THEN 'CONVERT(VARCHAR, LEFT(CONVERT(CHAR(22), CONVERT(MONEY, physical_io_delta), 1), 19)) ' - ELSE 'physical_io_delta ' - END + - 'ELSE NULL ' + - 'END AS physical_io_delta, ' + - --reads_delta - 'CASE ' + - 'WHEN ' + - 'first_request_start_time = last_request_start_time ' + - 'AND num_events = 2 ' + - 'AND reads_delta >= 0 ' + - 'THEN ' + - CASE @format_output - WHEN 1 THEN 'CONVERT(VARCHAR, SPACE(MAX(LEN(CONVERT(VARCHAR, reads_delta))) OVER() - LEN(CONVERT(VARCHAR, reads_delta))) + LEFT(CONVERT(CHAR(22), CONVERT(MONEY, reads_delta), 1), 19)) ' - WHEN 2 THEN 'CONVERT(VARCHAR, LEFT(CONVERT(CHAR(22), CONVERT(MONEY, reads_delta), 1), 19)) ' - ELSE 'reads_delta ' - END + - 'ELSE NULL ' + - 'END AS reads_delta, ' + - --physical_reads_delta - 'CASE ' + - 'WHEN ' + - 'first_request_start_time = last_request_start_time ' + - 'AND num_events = 2 ' + - 'AND physical_reads_delta >= 0 ' + - 'THEN ' + - CASE @format_output - WHEN 1 THEN 'CONVERT(VARCHAR, SPACE(MAX(LEN(CONVERT(VARCHAR, physical_reads_delta))) OVER() - LEN(CONVERT(VARCHAR, physical_reads_delta))) + LEFT(CONVERT(CHAR(22), CONVERT(MONEY, physical_reads_delta), 1), 19)) ' - WHEN 2 THEN 'CONVERT(VARCHAR, LEFT(CONVERT(CHAR(22), CONVERT(MONEY, physical_reads_delta), 1), 19)) ' - ELSE 'physical_reads_delta ' - END + - 'ELSE NULL ' + - 'END AS physical_reads_delta, ' + - --writes_delta - 'CASE ' + - 'WHEN ' + - 'first_request_start_time = last_request_start_time ' + - 'AND num_events = 2 ' + - 'AND writes_delta >= 0 ' + - 'THEN ' + - CASE @format_output - WHEN 1 THEN 'CONVERT(VARCHAR, SPACE(MAX(LEN(CONVERT(VARCHAR, writes_delta))) OVER() - LEN(CONVERT(VARCHAR, writes_delta))) + LEFT(CONVERT(CHAR(22), CONVERT(MONEY, writes_delta), 1), 19)) ' - WHEN 2 THEN 'CONVERT(VARCHAR, LEFT(CONVERT(CHAR(22), CONVERT(MONEY, writes_delta), 1), 19)) ' - ELSE 'writes_delta ' - END + - 'ELSE NULL ' + - 'END AS writes_delta, ' + - --tempdb_allocations_delta - 'CASE ' + - 'WHEN ' + - 'first_request_start_time = last_request_start_time ' + - 'AND num_events = 2 ' + - 'AND tempdb_allocations_delta >= 0 ' + - 'THEN ' + - CASE @format_output - WHEN 1 THEN 'CONVERT(VARCHAR, SPACE(MAX(LEN(CONVERT(VARCHAR, tempdb_allocations_delta))) OVER() - LEN(CONVERT(VARCHAR, tempdb_allocations_delta))) + LEFT(CONVERT(CHAR(22), CONVERT(MONEY, tempdb_allocations_delta), 1), 19)) ' - WHEN 2 THEN 'CONVERT(VARCHAR, LEFT(CONVERT(CHAR(22), CONVERT(MONEY, tempdb_allocations_delta), 1), 19)) ' - ELSE 'tempdb_allocations_delta ' - END + - 'ELSE NULL ' + - 'END AS tempdb_allocations_delta, ' + - --tempdb_current_delta - --this is the only one that can (legitimately) go negative - 'CASE ' + - 'WHEN ' + - 'first_request_start_time = last_request_start_time ' + - 'AND num_events = 2 ' + - 'THEN ' + - CASE @format_output - WHEN 1 THEN 'CONVERT(VARCHAR, SPACE(MAX(LEN(CONVERT(VARCHAR, tempdb_current_delta))) OVER() - LEN(CONVERT(VARCHAR, tempdb_current_delta))) + LEFT(CONVERT(CHAR(22), CONVERT(MONEY, tempdb_current_delta), 1), 19)) ' - WHEN 2 THEN 'CONVERT(VARCHAR, LEFT(CONVERT(CHAR(22), CONVERT(MONEY, tempdb_current_delta), 1), 19)) ' - ELSE 'tempdb_current_delta ' - END + - 'ELSE NULL ' + - 'END AS tempdb_current_delta, ' + - --CPU_delta - 'CASE ' + - 'WHEN ' + - 'first_request_start_time = last_request_start_time ' + - 'AND num_events = 2 ' + - 'THEN ' + - 'CASE ' + - 'WHEN ' + - 'thread_CPU_delta > CPU_delta ' + - 'AND thread_CPU_delta > 0 ' + - 'THEN ' + - CASE @format_output - WHEN 1 THEN 'CONVERT(VARCHAR, SPACE(MAX(LEN(CONVERT(VARCHAR, thread_CPU_delta + CPU_delta))) OVER() - LEN(CONVERT(VARCHAR, thread_CPU_delta))) + LEFT(CONVERT(CHAR(22), CONVERT(MONEY, thread_CPU_delta), 1), 19)) ' - WHEN 2 THEN 'CONVERT(VARCHAR, LEFT(CONVERT(CHAR(22), CONVERT(MONEY, thread_CPU_delta), 1), 19)) ' - ELSE 'thread_CPU_delta ' - END + - 'WHEN CPU_delta >= 0 THEN ' + - CASE @format_output - WHEN 1 THEN 'CONVERT(VARCHAR, SPACE(MAX(LEN(CONVERT(VARCHAR, thread_CPU_delta + CPU_delta))) OVER() - LEN(CONVERT(VARCHAR, CPU_delta))) + LEFT(CONVERT(CHAR(22), CONVERT(MONEY, CPU_delta), 1), 19)) ' - WHEN 2 THEN 'CONVERT(VARCHAR, LEFT(CONVERT(CHAR(22), CONVERT(MONEY, CPU_delta), 1), 19)) ' - ELSE 'CPU_delta ' - END + - 'ELSE NULL ' + - 'END ' + - 'ELSE ' + - 'NULL ' + - 'END AS CPU_delta, ' + - --context_switches_delta - 'CASE ' + - 'WHEN ' + - 'first_request_start_time = last_request_start_time ' + - 'AND num_events = 2 ' + - 'AND context_switches_delta >= 0 ' + - 'THEN ' + - CASE @format_output - WHEN 1 THEN 'CONVERT(VARCHAR, SPACE(MAX(LEN(CONVERT(VARCHAR, context_switches_delta))) OVER() - LEN(CONVERT(VARCHAR, context_switches_delta))) + LEFT(CONVERT(CHAR(22), CONVERT(MONEY, context_switches_delta), 1), 19)) ' - WHEN 2 THEN 'CONVERT(VARCHAR, LEFT(CONVERT(CHAR(22), CONVERT(MONEY, context_switches_delta), 1), 19)) ' - ELSE 'context_switches_delta ' - END + - 'ELSE NULL ' + - 'END AS context_switches_delta, ' + - --used_memory_delta - 'CASE ' + - 'WHEN ' + - 'first_request_start_time = last_request_start_time ' + - 'AND num_events = 2 ' + - 'AND used_memory_delta >= 0 ' + - 'THEN ' + - CASE @format_output - WHEN 1 THEN 'CONVERT(VARCHAR, SPACE(MAX(LEN(CONVERT(VARCHAR, used_memory_delta))) OVER() - LEN(CONVERT(VARCHAR, used_memory_delta))) + LEFT(CONVERT(CHAR(22), CONVERT(MONEY, used_memory_delta), 1), 19)) ' - WHEN 2 THEN 'CONVERT(VARCHAR, LEFT(CONVERT(CHAR(22), CONVERT(MONEY, used_memory_delta), 1), 19)) ' - ELSE 'used_memory_delta ' - END + - 'ELSE NULL ' + - 'END AS used_memory_delta, ' - ELSE '' - END + - --tasks - CASE @format_output - WHEN 1 THEN 'CONVERT(VARCHAR, SPACE(MAX(LEN(CONVERT(VARCHAR, tasks))) OVER() - LEN(CONVERT(VARCHAR, tasks))) + LEFT(CONVERT(CHAR(22), CONVERT(MONEY, tasks), 1), 19)) AS ' - WHEN 2 THEN 'CONVERT(VARCHAR, LEFT(CONVERT(CHAR(22), CONVERT(MONEY, tasks), 1), 19)) ' - ELSE '' - END + 'tasks, ' + - 'status, ' + - 'wait_info, ' + - 'locks, ' + - 'tran_start_time, ' + - 'LEFT(tran_log_writes, LEN(tran_log_writes) - 1) AS tran_log_writes, ' + - --open_tran_count - CASE @format_output - WHEN 1 THEN 'CONVERT(VARCHAR, SPACE(MAX(LEN(CONVERT(VARCHAR, open_tran_count))) OVER() - LEN(CONVERT(VARCHAR, open_tran_count))) + LEFT(CONVERT(CHAR(22), CONVERT(MONEY, open_tran_count), 1), 19)) AS ' - WHEN 2 THEN 'CONVERT(VARCHAR, LEFT(CONVERT(CHAR(22), CONVERT(MONEY, open_tran_count), 1), 19)) AS ' - ELSE '' - END + 'open_tran_count, ' + - --sql_command - CASE @format_output - WHEN 0 THEN 'REPLACE(REPLACE(CONVERT(NVARCHAR(MAX), sql_command), '''', '''') AS ' - ELSE '' - END + 'sql_command, ' + - --sql_text - CASE @format_output - WHEN 0 THEN 'REPLACE(REPLACE(CONVERT(NVARCHAR(MAX), sql_text), '''', '''') AS ' - ELSE '' - END + 'sql_text, ' + - 'query_plan, ' + - 'blocking_session_id, ' + - --blocked_session_count - CASE @format_output - WHEN 1 THEN 'CONVERT(VARCHAR, SPACE(MAX(LEN(CONVERT(VARCHAR, blocked_session_count))) OVER() - LEN(CONVERT(VARCHAR, blocked_session_count))) + LEFT(CONVERT(CHAR(22), CONVERT(MONEY, blocked_session_count), 1), 19)) AS ' - WHEN 2 THEN 'CONVERT(VARCHAR, LEFT(CONVERT(CHAR(22), CONVERT(MONEY, blocked_session_count), 1), 19)) AS ' - ELSE '' - END + 'blocked_session_count, ' + - --percent_complete - CASE @format_output - WHEN 1 THEN 'CONVERT(VARCHAR, SPACE(MAX(LEN(CONVERT(VARCHAR, CONVERT(MONEY, percent_complete), 2))) OVER() - LEN(CONVERT(VARCHAR, CONVERT(MONEY, percent_complete), 2))) + CONVERT(CHAR(22), CONVERT(MONEY, percent_complete), 2)) AS ' - WHEN 2 THEN 'CONVERT(VARCHAR, CONVERT(CHAR(22), CONVERT(MONEY, blocked_session_count), 1)) AS ' - ELSE '' - END + 'percent_complete, ' + - 'host_name, ' + - 'login_name, ' + - 'database_name, ' + - 'program_name, ' + - 'additional_info, ' + - 'start_time, ' + - 'login_time, ' + - 'CASE ' + - 'WHEN status = N''sleeping'' THEN NULL ' + - 'ELSE request_id ' + - 'END AS request_id, ' + - 'GETDATE() AS collection_time ' - --End inner column list - ) + - --Derived table and INSERT specification - CONVERT - ( - VARCHAR(MAX), - 'FROM ' + - '( ' + - 'SELECT TOP(2147483647) ' + - '*, ' + - 'CASE ' + - 'MAX ' + - '( ' + - 'LEN ' + - '( ' + - 'CONVERT ' + - '( ' + - 'VARCHAR, ' + - 'CASE ' + - 'WHEN elapsed_time < 0 THEN ' + - '(-1 * elapsed_time) / 86400 ' + - 'ELSE ' + - 'elapsed_time / 86400000 ' + - 'END ' + - ') ' + - ') ' + - ') OVER () ' + - 'WHEN 1 THEN 2 ' + - 'ELSE ' + - 'MAX ' + - '( ' + - 'LEN ' + - '( ' + - 'CONVERT ' + - '( ' + - 'VARCHAR, ' + - 'CASE ' + - 'WHEN elapsed_time < 0 THEN ' + - '(-1 * elapsed_time) / 86400 ' + - 'ELSE ' + - 'elapsed_time / 86400000 ' + - 'END ' + - ') ' + - ') ' + - ') OVER () ' + - 'END AS max_elapsed_length, ' + - CASE - WHEN @output_column_list LIKE '%|_delta|]%' ESCAPE '|' THEN - 'MAX(physical_io * recursion) OVER (PARTITION BY session_id, request_id) + ' + - 'MIN(physical_io * recursion) OVER (PARTITION BY session_id, request_id) AS physical_io_delta, ' + - 'MAX(reads * recursion) OVER (PARTITION BY session_id, request_id) + ' + - 'MIN(reads * recursion) OVER (PARTITION BY session_id, request_id) AS reads_delta, ' + - 'MAX(physical_reads * recursion) OVER (PARTITION BY session_id, request_id) + ' + - 'MIN(physical_reads * recursion) OVER (PARTITION BY session_id, request_id) AS physical_reads_delta, ' + - 'MAX(writes * recursion) OVER (PARTITION BY session_id, request_id) + ' + - 'MIN(writes * recursion) OVER (PARTITION BY session_id, request_id) AS writes_delta, ' + - 'MAX(tempdb_allocations * recursion) OVER (PARTITION BY session_id, request_id) + ' + - 'MIN(tempdb_allocations * recursion) OVER (PARTITION BY session_id, request_id) AS tempdb_allocations_delta, ' + - 'MAX(tempdb_current * recursion) OVER (PARTITION BY session_id, request_id) + ' + - 'MIN(tempdb_current * recursion) OVER (PARTITION BY session_id, request_id) AS tempdb_current_delta, ' + - 'MAX(CPU * recursion) OVER (PARTITION BY session_id, request_id) + ' + - 'MIN(CPU * recursion) OVER (PARTITION BY session_id, request_id) AS CPU_delta, ' + - 'MAX(thread_CPU_snapshot * recursion) OVER (PARTITION BY session_id, request_id) + ' + - 'MIN(thread_CPU_snapshot * recursion) OVER (PARTITION BY session_id, request_id) AS thread_CPU_delta, ' + - 'MAX(context_switches * recursion) OVER (PARTITION BY session_id, request_id) + ' + - 'MIN(context_switches * recursion) OVER (PARTITION BY session_id, request_id) AS context_switches_delta, ' + - 'MAX(used_memory * recursion) OVER (PARTITION BY session_id, request_id) + ' + - 'MIN(used_memory * recursion) OVER (PARTITION BY session_id, request_id) AS used_memory_delta, ' + - 'MIN(last_request_start_time) OVER (PARTITION BY session_id, request_id) AS first_request_start_time, ' - ELSE '' - END + - 'COUNT(*) OVER (PARTITION BY session_id, request_id) AS num_events ' + - 'FROM #sessions AS s1 ' + - CASE - WHEN @sort_order = '' THEN '' - ELSE - 'ORDER BY ' + - @sort_order - END + - ') AS s ' + - 'WHERE ' + - 's.recursion = 1 ' + - ') x ' + - 'OPTION (KEEPFIXED PLAN); ' + - '' + - CASE @return_schema - WHEN 1 THEN - 'SET @schema = ' + - '''CREATE TABLE ( '' + ' + - 'STUFF ' + - '( ' + - '( ' + - 'SELECT ' + - ''','' + ' + - 'QUOTENAME(COLUMN_NAME) + '' '' + ' + - 'DATA_TYPE + ' + - 'CASE ' + - 'WHEN DATA_TYPE LIKE ''%char'' THEN ''('' + COALESCE(NULLIF(CONVERT(VARCHAR, CHARACTER_MAXIMUM_LENGTH), ''-1''), ''max'') + '') '' ' + - 'ELSE '' '' ' + - 'END + ' + - 'CASE IS_NULLABLE ' + - 'WHEN ''NO'' THEN ''NOT '' ' + - 'ELSE '''' ' + - 'END + ''NULL'' AS [text()] ' + - 'FROM tempdb.INFORMATION_SCHEMA.COLUMNS ' + - 'WHERE ' + - 'TABLE_NAME = (SELECT name FROM tempdb.sys.objects WHERE object_id = OBJECT_ID(''tempdb..#session_schema'')) ' + - 'ORDER BY ' + - 'ORDINAL_POSITION ' + - 'FOR XML ' + - 'PATH('''') ' + - '), + ' + - '1, ' + - '1, ' + - ''''' ' + - ') + ' + - ''')''; ' - ELSE '' - END - --End derived table and INSERT specification - ); - - SET @sql_n = CONVERT(NVARCHAR(MAX), @sql); - - EXEC sp_executesql - @sql_n, - N'@schema VARCHAR(MAX) OUTPUT', - @schema OUTPUT; -END; -GO diff --git a/QueryTemplates/disk-info.sql b/QueryTemplates/disk-info.sql new file mode 100644 index 0000000..752b3c7 --- /dev/null +++ b/QueryTemplates/disk-info.sql @@ -0,0 +1,10 @@ +SELECT DISTINCT + vs.volume_mount_point, + vs.file_system_type, + vs.logical_volume_name, + CONVERT(DECIMAL (18, 2), vs.total_bytes / 1024.0 / 1024 / 1024) AS [Total Size (GB)], + CONVERT(DECIMAL (18, 2), vs.available_bytes / 1024.0 / 1024 / 1024) AS [Available Size (GB)], + CONVERT(DECIMAL (18, 2), vs.available_bytes * 1. / vs.total_bytes * 100.) AS [Space Free %] +FROM sys.master_files AS f WITH (NOLOCK) CROSS APPLY sys.dm_os_volume_stats(f.database_id, f.[file_id]) AS vs +ORDER BY vs.volume_mount_point +OPTION (RECOMPILE); diff --git a/QueryTemplates/indexes-stat.sql b/QueryTemplates/indexes-stat.sql new file mode 100644 index 0000000..6f40bdd --- /dev/null +++ b/QueryTemplates/indexes-stat.sql @@ -0,0 +1,27 @@ +SELECT SCHEMA_NAME(o.schema_id) AS SchemaName, + OBJECT_NAME(p.object_id) AS ObjectName, + i.[name] AS IndexName, + p.index_id AS IndexID, + p.partition_number AS PartitionNumber, + FORMAT(p.[rows], 'N0') AS [Rows], + FORMAT(a.total_pages * 8 / 1024., 'N2') AS IndexSizeMb, --doesn't include LOB + p.[data_compression_desc] AS [Compression], + CONCAT('ALTER INDEX [', i.[name], '] ON [', SCHEMA_NAME(o.schema_id), '].[', OBJECT_NAME(p.object_id), '] REBUILD PARTITION = ', + CASE WHEN EXISTS (SELECT TOP 1 1 FROM sys.partition_schemes AS ps WHERE ps.data_space_id = i.data_space_id) + THEN CAST (p.partition_number AS VARCHAR (4)) ELSE 'ALL' END, + ' WITH (ONLINE = ON (WAIT_AT_LOW_PRIORITY (MAX_DURATION = 15 MINUTES, ABORT_AFTER_WAIT = SELF)), ', + 'SORT_IN_TEMPDB = ON, DATA_COMPRESSION=PAGE, MAXDOP = 8);') + CHAR(13) + CHAR(10) + 'GO' AS RebuildCommand +FROM sys.partitions AS p + INNER JOIN sys.indexes AS i ON i.[object_id] = p.[object_id] AND i.index_id = p.index_id + INNER JOIN sys.tables AS o ON i.[object_id] = o.[object_id] + INNER JOIN sys.data_spaces AS ds ON ds.data_space_id = i.data_space_id + LEFT OUTER JOIN sys.allocation_units AS a ON p.[partition_id] = a.container_id AND a.data_pages > 0 AND a.total_pages > 0 -- B-tree only I guess +WHERE 1 = 1 + -- AND i.index_id = 1 + -- AND OBJECT_NAME(p.[object_id]) = '' + -- AND SCHEMA_NAME(o.[schema_id]) = '' + -- AND i.[name] = '' + -- AND p.partition_number = 0 + -- AND p.[rows] > 0 +ORDER BY ObjectName, PartitionNumber, IndexID; + diff --git a/QueryTemplates/sp_WhoIsActive.sql b/QueryTemplates/sp_WhoIsActive.sql new file mode 100644 index 0000000..663db82 --- /dev/null +++ b/QueryTemplates/sp_WhoIsActive.sql @@ -0,0 +1,5 @@ +EXEC sp_WhoIsActive @show_sleeping_spids = 0 + --,@get_plans = 1 + --,@get_outer_command = 1 + --,@get_locks = 1 + --,@find_block_leaders = 1; diff --git a/QueryTemplates/sysprocesses.sql b/QueryTemplates/sysprocesses.sql index 9c6a8eb..0e44616 100644 --- a/QueryTemplates/sysprocesses.sql +++ b/QueryTemplates/sysprocesses.sql @@ -2,6 +2,8 @@ SELECT ec.client_net_address, es.[program_name], es.[host_name], es.login_name, + ec.local_net_address, + ec.local_tcp_port, DB_NAME(es.database_id) as DatabaseName, COUNT(ec.session_id) AS [connection count], SUM(CASE WHEN encrypt_option = 'TRUE' THEN 1 ELSE 0 END) AS [connection count (enc)] @@ -12,7 +14,12 @@ FROM sys.dm_exec_sessions AS es WITH (NOLOCK) WHERE 1 = 1 -- AND es.[program_name] LIKE '%%' -- AND DB_NAME(es.database_id) = '' - -- AND es.[host_name] LIKE '%%' -GROUP BY ec.client_net_address, es.[program_name], es.[host_name], es.login_name, DB_NAME(es.database_id) -ORDER BY ec.client_net_address, es.[program_name] + -- AND es.[host_name] LIKE '%%' + -- AND es.login_name = '' +GROUP BY + GROUPING SETS((), --totals + (ec.client_net_address, es.[program_name], es.[host_name], es.login_name, ec.local_net_address, ec.local_tcp_port, DB_NAME(es.database_id))) +ORDER BY + ec.client_net_address, es.[program_name] + -- [connection count] DESC OPTION (RECOMPILE); diff --git a/QueryTemplates/tables-info.sql b/QueryTemplates/tables-info.sql new file mode 100644 index 0000000..576e3b8 --- /dev/null +++ b/QueryTemplates/tables-info.sql @@ -0,0 +1,102 @@ +SET NOCOUNT ON; +DECLARE @RowsStatistics AS TABLE (ObjectId INT, PartitionCount INT, RowsCount BIGINT, UnusedPagesPercent INT, INDEX IDX CLUSTERED (ObjectId)); +INSERT INTO @RowsStatistics +SELECT ps.object_id AS ObjectId, + COUNT(DISTINCT ps.partition_number) AS PartitionCount, + SUM(ps.row_count) AS RowsCount, + CASE WHEN SUM(ps.reserved_page_count) = 0 THEN 0 ELSE (SUM(ps.reserved_page_count) - SUM(ps.used_page_count)) * 100 / SUM(ps.reserved_page_count) END AS UnusedPagesPercent +FROM sys.dm_db_partition_stats AS ps + INNER JOIN sys.objects AS so ON ps.object_id = so.object_id +WHERE ps.index_id < 2 +GROUP BY ps.object_id; + +DECLARE @TableInfo AS TABLE (SchemaName SYSNAME, TableName SYSNAME, ObjectId INT, HasPK INT, HasClusteredIndex INT, PKisClustered INT, IsReplicated INT, IndexCount INT, CreateDate DATETIME, LastIdentityValue SQL_VARIANT NULL, IdentityType SYSNAME NULL, INDEX IDX CLUSTERED (ObjectId)); +INSERT INTO @TableInfo +SELECT + OBJECT_SCHEMA_NAME(t.object_id) AS SchemaName, + OBJECT_NAME(t.object_id) AS TableName, + t.object_id AS ObjectId, + i.HasPK, + i.HasClusteredIndex, + i.PKisClustered, + t.is_replicated as IsReplicated, + COALESCE (i.IndexCount, 0) AS IndexCount, + t.create_date, + ic.last_value, + st.name +FROM sys.tables AS t + LEFT OUTER JOIN + (SELECT si.object_id, + COUNT(CASE WHEN si.type_desc = 'HEAP' THEN NULL ELSE 1 END) AS IndexCount, + SUM(CASE WHEN si.type_desc = 'CLUSTERED' THEN 1 ELSE 0 END) AS HasClusteredIndex, + SUM(CASE WHEN si.is_primary_key = 1 THEN 1 ELSE 0 END) AS HasPK, + SUM(CASE WHEN si.type_desc = 'CLUSTERED' + AND si.is_primary_key = 1 THEN 1 ELSE 0 END) AS PKisClustered + FROM sys.indexes AS si + GROUP BY si.object_id) AS i + ON t.object_id = i.object_id + LEFT JOIN sys.identity_columns ic ON t.object_id = ic.object_id + LEFT JOIN sys.types st ON ic.system_type_id = st.system_type_id AND ic.user_type_id = st.user_type_id +WHERE t.is_ms_shipped = 0; + +DECLARE @TableSizes AS TABLE (ObjectId INT, UsedSpaceMB NUMERIC (36, 2), UsedSpaceMB_Compressed NUMERIC (36, 2), UsedSpaceMB_LOB NUMERIC (36, 2), UsedSpaceMB_CS NUMERIC (36, 2), INDEX IDX CLUSTERED (ObjectId)); +INSERT INTO @TableSizes +SELECT t.object_id AS ObjectId, + CAST (ROUND(((SUM(a.used_pages) * 8) / 1024.00), 2) AS NUMERIC (36, 2)) AS UsedSpaceMB, + CAST (ROUND(((SUM(CASE WHEN p.[data_compression] > 0 THEN a.used_pages ELSE 0 END) * 8) / 1024.00), 2) AS NUMERIC (36, 2)) AS UsedSpaceMB_Compressed, + CAST (ROUND(((SUM(CASE WHEN a.[type_desc] = 'LOB_DATA' AND i.[type] in (1, 2) THEN a.used_pages ELSE 0 END) * 8) / 1024.00), 2) AS NUMERIC (36, 2)) AS UsedSpaceMB_LOB, + CAST (ROUND(((SUM(CASE WHEN i.[type] in (5, 6) THEN a.used_pages ELSE 0 END) * 8) / 1024.00), 2) AS NUMERIC (36, 2)) AS UsedSpaceMB_CS +FROM sys.tables AS t + INNER JOIN sys.indexes AS i ON t.object_id = i.object_id + INNER JOIN sys.partitions AS p ON i.object_id = p.object_id AND i.index_id = p.index_id + INNER JOIN sys.allocation_units AS a ON p.partition_id = a.container_id +GROUP BY t.object_id; + +DECLARE @LastReadWrites AS TABLE (ObjectId INT, [LastWrite] DATETIME, [LastRead] DATETIME, [TotalReads] BIGINT, [TotalWrites] BIGINT, INDEX IDX CLUSTERED (ObjectId)); +INSERT INTO @LastReadWrites +SELECT ObjectID AS ObjectID, + MAX([LastUserUpdate]) AS [LastWrite], + MAX([LastUserRead]) AS [LastRead], + SUM([TotalReads]) AS [TotalReads], + SUM([TotalWrites]) AS [TotalWrites] +FROM (SELECT object_id AS ObjectID, + (last_user_update) AS [LastUserUpdate], + (SELECT Max(v) FROM (VALUES (last_user_seek), (last_user_scan), (last_user_lookup)) AS value(v)) AS [LastUserRead], + (user_updates) AS [TotalWrites], + (user_seeks + user_scans + user_lookups) AS [TotalReads] + FROM sys.dm_db_index_usage_stats + WHERE database_id = DB_ID()) AS a +GROUP BY ObjectID; + +SELECT DB_NAME() AS DatabaseName, + ti.SchemaName, + ti.TableName, + FORMAT(RS.RowsCount, 'N0') AS RowsCount, + FORMAT(TS.UsedSpaceMB, 'N0') AS UsedSpaceMB, + -- FORMAT(TS.UsedSpaceMB_LOB, 'N0') AS UsedSpaceMB_LOB, + -- FORMAT(TS.UsedSpaceMB_CS, 'N0') AS UsedSpaceMB_CS, + FORMAT(TS.UsedSpaceMB_Compressed, 'N0') AS UsedSpaceMB_ZIP, + RS.PartitionCount, + ti.IndexCount, + ti.HasPK, + ti.HasClusteredIndex, + ti.PKisClustered, + ti.IsReplicated, + L.LastWrite, + L.LastRead, + L.TotalReads, + L.TotalWrites, + ti.CreateDate, + RS.UnusedPagesPercent, + ti.LastIdentityValue, + ti.IdentityType +FROM @TableInfo AS ti + LEFT JOIN @RowsStatistics AS RS ON RS.ObjectId = ti.ObjectId + LEFT JOIN @LastReadWrites AS L ON L.ObjectId = RS.ObjectId + LEFT JOIN @TableSizes AS TS ON TS.ObjectId = ti.ObjectId +WHERE 1 = 1 + --AND ti.TableName IN ('','') + --AND ti.SchemaName = '' + --AND RS.RowsCount > 0 +ORDER BY TS.UsedSpaceMB DESC; +-- ORDER BY TS.UsedSpaceMB - TS.UsedSpaceMB_LOB DESC; diff --git a/QueryTemplates/trn-log-info.sql b/QueryTemplates/trn-log-info.sql new file mode 100644 index 0000000..8c55190 --- /dev/null +++ b/QueryTemplates/trn-log-info.sql @@ -0,0 +1,30 @@ +SELECT db.[name] AS [Database Name], SUSER_SNAME(db.owner_sid) AS [Database Owner], +db.[compatibility_level] AS [DB Compatibility Level], +db.recovery_model_desc AS [Recovery Model], +db.log_reuse_wait_desc AS [Log Reuse Wait Description], +CONVERT(DECIMAL(18,2), ds.cntr_value/1024.0) AS [Total Data File Size on Disk (MB)], +CONVERT(DECIMAL(18,2), ls.cntr_value/1024.0) AS [Total Log File Size on Disk (MB)], +CONVERT(DECIMAL(18,2), lu.cntr_value/1024.0) AS [Log File Used (MB)], +CAST(CAST(lu.cntr_value AS FLOAT) / CAST(ls.cntr_value AS FLOAT)AS DECIMAL(18,2)) * 100 AS [Log Used %], +db.page_verify_option_desc AS [Page Verify Option], db.user_access_desc, db.state_desc, db.containment_desc, --db.is_mixed_page_allocation_on, +db.is_auto_create_stats_on, db.is_auto_update_stats_on, db.is_auto_update_stats_async_on, db.is_parameterization_forced, +db.snapshot_isolation_state_desc, db.is_read_committed_snapshot_on, db.is_auto_close_on, db.is_auto_shrink_on, +db.target_recovery_time_in_seconds, db.is_cdc_enabled, db.is_published, db.is_distributor, db.is_sync_with_backup, +db.group_database_id, db.replica_id, --db.is_memory_optimized_enabled, +db.is_memory_optimized_elevate_to_snapshot_on, db.delayed_durability_desc, db.is_query_store_on, +-- db.is_temporal_history_retention_enabled, db.is_accelerated_database_recovery_on, +db.is_master_key_encrypted_by_server, db.is_encrypted, de.encryption_state, de.percent_complete, de.key_algorithm, de.key_length +FROM sys.databases AS db WITH (NOLOCK) +LEFT OUTER JOIN sys.dm_os_performance_counters AS lu WITH (NOLOCK) +ON db.name = lu.instance_name +LEFT OUTER JOIN sys.dm_os_performance_counters AS ls WITH (NOLOCK) +ON db.name = ls.instance_name +LEFT OUTER JOIN sys.dm_os_performance_counters AS ds WITH (NOLOCK) +ON db.name = ds.instance_name +LEFT OUTER JOIN sys.dm_database_encryption_keys AS de WITH (NOLOCK) +ON db.database_id = de.database_id +WHERE lu.counter_name LIKE N'Log File(s) Used Size (KB)%' +AND ls.counter_name LIKE N'Log File(s) Size (KB)%' +AND ds.counter_name LIKE N'Data File(s) Size (KB)%' +AND ls.cntr_value > 0 +ORDER BY db.[name] OPTION (RECOMPILE); diff --git a/README.md b/README.md index bd4e79f..c43dc5a 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,8 @@ +> [!WARNING] +> # Repository Archived +> This repository is no longer active, as we have moved to a newer version. For the latest updates and features, please visit the new repository at [Axial SQL Tools](https://github.com/Axial-SQL/AxialSqlTools). We encourage you to check out the new version for the most up-to-date tools and improvements. + +

SQL Server Management Studio 2018 Productivity Tool (Addin)

Work in progress... I had to make it as an "ugly" toolbox window because I couldn't figure out how to make a dynamic menu in a toolbar.

    @@ -7,7 +12,7 @@

    .NET 4.7.2 is required.

    -

    To install the addin unpack files from the most recent release into C:\Program Files (x86)\Microsoft SQL Server Management Studio 18\Common7\IDE\Extensions folder.

    +

    To install the addin unpack files from the most recent release into C:\Program Files (x86)\Microsoft SQL Server Management Studio 18\Common7\IDE\Extensions folder.