diff --git a/Documentation/sp_Blitz_Checks_by_Priority.md b/Documentation/sp_Blitz_Checks_by_Priority.md index 5c12ec039..8f964ffe5 100644 --- a/Documentation/sp_Blitz_Checks_by_Priority.md +++ b/Documentation/sp_Blitz_Checks_by_Priority.md @@ -6,8 +6,8 @@ Before adding a new check, make sure to add a Github issue for it first, and hav If you want to change anything about a check - the priority, finding, URL, or ID - open a Github issue first. The relevant scripts have to be updated too. -CURRENT HIGH CHECKID: 266. -If you want to add a new one, start at 267. +CURRENT HIGH CHECKID: 267. +If you want to add a new one, start at 268. | Priority | FindingsGroup | Finding | URL | CheckID | |----------|-----------------------------|---------------------------------------------------------|------------------------------------------------------------------------|----------| @@ -276,6 +276,7 @@ If you want to add a new one, start at 267. | 210 | Non-Default Database Scoped Config | Legacy CE | https://www.BrentOzar.com/go/dbscope | 195 | | 210 | Non-Default Database Scoped Config | Parameter Sniffing | https://www.BrentOzar.com/go/dbscope | 196 | | 210 | Non-Default Database Scoped Config | Query Optimizer Hotfixes | https://www.BrentOzar.com/go/dbscope | 197 | +| 210 | Non-Default Database Scoped Config | All Others | https://www.BrentOzar.com/go/dbscope | 267 | | 230 | Security | Control Server Permissions | https://www.BrentOzar.com/go/sa | 104 | | 230 | Security | Database Owner <> SA | https://www.BrentOzar.com/go/owndb | 55 | | 230 | Security | Database Owner is Unknown | | 213 | diff --git a/sp_Blitz.sql b/sp_Blitz.sql index 517c62e6a..e568f5886 100644 --- a/sp_Blitz.sql +++ b/sp_Blitz.sql @@ -7749,52 +7749,44 @@ IF @ProductVersionMajor >= 10 IF @Debug IN (1, 2) RAISERROR('Running CheckId [%d] through [%d] and [%d] through [%d].', 0, 1, 194, 197, 237, 255) WITH NOWAIT; INSERT INTO #DatabaseScopedConfigurationDefaults (configuration_id, [name], default_value, default_value_for_secondary, CheckID) - SELECT 1, 'MAXDOP', '0', NULL, 194 - UNION ALL - SELECT 2, 'LEGACY_CARDINALITY_ESTIMATION', '0', NULL, 195 - UNION ALL - SELECT 3, 'PARAMETER_SNIFFING', '1', NULL, 196 - UNION ALL - SELECT 4, 'QUERY_OPTIMIZER_HOTFIXES', '0', NULL, 197 - UNION ALL - SELECT 6, 'IDENTITY_CACHE', '1', NULL, 237 - UNION ALL - SELECT 7, 'INTERLEAVED_EXECUTION_TVF', '1', NULL, 238 - UNION ALL - SELECT 8, 'BATCH_MODE_MEMORY_GRANT_FEEDBACK', '1', NULL, 239 - UNION ALL - SELECT 9, 'BATCH_MODE_ADAPTIVE_JOINS', '1', NULL, 240 - UNION ALL - SELECT 10, 'TSQL_SCALAR_UDF_INLINING', '1', NULL, 241 - UNION ALL - SELECT 11, 'ELEVATE_ONLINE', 'OFF', NULL, 242 - UNION ALL - SELECT 12, 'ELEVATE_RESUMABLE', 'OFF', NULL, 243 - UNION ALL - SELECT 13, 'OPTIMIZE_FOR_AD_HOC_WORKLOADS', '0', NULL, 244 - UNION ALL - SELECT 14, 'XTP_PROCEDURE_EXECUTION_STATISTICS', '0', NULL, 245 - UNION ALL - SELECT 15, 'XTP_QUERY_EXECUTION_STATISTICS', '0', NULL, 246 - UNION ALL - SELECT 16, 'ROW_MODE_MEMORY_GRANT_FEEDBACK', '1', NULL, 247 - UNION ALL - SELECT 17, 'ISOLATE_SECURITY_POLICY_CARDINALITY', '0', NULL, 248 - UNION ALL - SELECT 18, 'BATCH_MODE_ON_ROWSTORE', '1', NULL, 249 - UNION ALL - SELECT 19, 'DEFERRED_COMPILATION_TV', '1', NULL, 250 - UNION ALL - SELECT 20, 'ACCELERATED_PLAN_FORCING', '1', NULL, 251 - UNION ALL - SELECT 21, 'GLOBAL_TEMPORARY_TABLE_AUTO_DROP', '1', NULL, 252 - UNION ALL - SELECT 22, 'LIGHTWEIGHT_QUERY_PROFILING', '1', NULL, 253 - UNION ALL - SELECT 23, 'VERBOSE_TRUNCATION_WARNINGS', '1', NULL, 254 - UNION ALL - SELECT 24, 'LAST_QUERY_PLAN_STATS', '0', NULL, 255; - EXEC dbo.sp_MSforeachdb 'USE [?]; SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED; INSERT INTO #BlitzResults (CheckID, DatabaseName, Priority, FindingsGroup, Finding, URL, Details) + VALUES + (1, 'MAXDOP', '0', NULL, 194), + (2, 'LEGACY_CARDINALITY_ESTIMATION', '0', NULL, 195), + (3, 'PARAMETER_SNIFFING', '1', NULL, 196), + (4, 'QUERY_OPTIMIZER_HOTFIXES', '0', NULL, 197), + (6, 'IDENTITY_CACHE', '1', NULL, 237), + (7, 'INTERLEAVED_EXECUTION_TVF', '1', NULL, 238), + (8, 'BATCH_MODE_MEMORY_GRANT_FEEDBACK', '1', NULL, 239), + (9, 'BATCH_MODE_ADAPTIVE_JOINS', '1', NULL, 240), + (10, 'TSQL_SCALAR_UDF_INLINING', '1', NULL, 241), + (11, 'ELEVATE_ONLINE', 'OFF', NULL, 242), + (12, 'ELEVATE_RESUMABLE', 'OFF', NULL, 243), + (13, 'OPTIMIZE_FOR_AD_HOC_WORKLOADS', '0', NULL, 244), + (14, 'XTP_PROCEDURE_EXECUTION_STATISTICS', '0', NULL, 245), + (15, 'XTP_QUERY_EXECUTION_STATISTICS', '0', NULL, 246), + (16, 'ROW_MODE_MEMORY_GRANT_FEEDBACK', '1', NULL, 247), + (17, 'ISOLATE_SECURITY_POLICY_CARDINALITY', '0', NULL, 248), + (18, 'BATCH_MODE_ON_ROWSTORE', '1', NULL, 249), + (19, 'DEFERRED_COMPILATION_TV', '1', NULL, 250), + (20, 'ACCELERATED_PLAN_FORCING', '1', NULL, 251), + (21, 'GLOBAL_TEMPORARY_TABLE_AUTO_DROP', '1', NULL, 252), + (22, 'LIGHTWEIGHT_QUERY_PROFILING', '1', NULL, 253), + (23, 'VERBOSE_TRUNCATION_WARNINGS', '1', NULL, 254), + (24, 'LAST_QUERY_PLAN_STATS', '0', NULL, 255), + (25, 'PAUSED_RESUMABLE_INDEX_ABORT_DURATION_MINUTES', '1440', NULL, 267), + (26, 'DW_COMPATIBILITY_LEVEL', '0', NULL, 267), + (27, 'EXEC_QUERY_STATS_FOR_SCALAR_FUNCTIONS', '1', NULL, 267), + (28, 'PARAMETER_SENSITIVE_PLAN_OPTIMIZATION', '1', NULL, 267), + (29, 'ASYNC_STATS_UPDATE_WAIT_AT_LOW_PRIORITY', '0', NULL, 267), + (31, 'CE_FEEDBACK', '1', NULL, 267), + (33, 'MEMORY_GRANT_FEEDBACK_PERSISTENCE', '1', NULL, 267), + (34, 'MEMORY_GRANT_FEEDBACK_PERCENTILE_GRANT', '1', NULL, 267), + (35, 'OPTIMIZED_PLAN_FORCING', '1', NULL, 267), + (37, 'DOP_FEEDBACK', '0', NULL, 267), + (38, 'LEDGER_DIGEST_STORAGE_ENDPOINT', 'OFF', NULL, 267), + (39, 'FORCE_SHOWPLAN_RUNTIME_PARAMETER_COLLECTION', '0', NULL, 267); + +EXEC dbo.sp_MSforeachdb 'USE [?]; SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED; INSERT INTO #BlitzResults (CheckID, DatabaseName, Priority, FindingsGroup, Finding, URL, Details) SELECT def1.CheckID, DB_NAME(), 210, ''Non-Default Database Scoped Config'', dsc.[name], ''https://www.brentozar.com/go/dbscope'', (''Set value: '' + COALESCE(CAST(dsc.value AS NVARCHAR(100)),''Empty'') + '' Default: '' + COALESCE(CAST(def1.default_value AS NVARCHAR(100)),''Empty'') + '' Set value for secondary: '' + COALESCE(CAST(dsc.value_for_secondary AS NVARCHAR(100)),''Empty'') + '' Default value for secondary: '' + COALESCE(CAST(def1.default_value_for_secondary AS NVARCHAR(100)),''Empty'')) FROM [?].sys.database_scoped_configurations dsc INNER JOIN #DatabaseScopedConfigurationDefaults def1 ON dsc.configuration_id = def1.configuration_id diff --git a/sp_BlitzIndex.sql b/sp_BlitzIndex.sql index 6ae4e5968..63519ff4a 100644 --- a/sp_BlitzIndex.sql +++ b/sp_BlitzIndex.sql @@ -131,6 +131,7 @@ DECLARE @ColumnList NVARCHAR(MAX); DECLARE @ColumnListWithApostrophes NVARCHAR(MAX); DECLARE @PartitionCount INT; DECLARE @OptimizeForSequentialKey BIT = 0; +DECLARE @ResumableIndexesDisappearAfter INT = 0; DECLARE @StringToExecute NVARCHAR(MAX); /* If user was lazy and just used @ObjectName with a fully qualified table name, then lets parse out the various parts */ @@ -2612,7 +2613,17 @@ OPTION (RECOMPILE);'; [object_id], index_id, name, sql_text, last_max_dop_used, partition_number, state, state_desc, start_time, last_pause_time, total_execution_time, percent_complete, page_count ) EXEC sp_executesql @dsql, @params = N'@i_DatabaseName NVARCHAR(128)', @i_DatabaseName = @DatabaseName; - END TRY + + SET @dsql=N'SELECT @ResumableIndexesDisappearAfter = CAST(value AS INT) + FROM ' + QUOTENAME(@DatabaseName) + N'.sys.database_scoped_configurations + WHERE name = ''PAUSED_RESUMABLE_INDEX_ABORT_DURATION_MINUTES'' + AND value > 0;' + EXEC sp_executesql @dsql, N'@ResumableIndexesDisappearAfter INT OUT', @ResumableIndexesDisappearAfter out; + + IF @ResumableIndexesDisappearAfter IS NULL + SET @ResumableIndexesDisappearAfter = 0; + + END TRY BEGIN CATCH RAISERROR (N'Skipping #IndexResumableOperations population due to error, typically low permissions', 0,1) WITH NOWAIT; END CATCH @@ -3294,17 +3305,22 @@ BEGIN SELECT N'Resumable Index Operation' AS finding, N'This may invalidate your analysis!' AS warning, - iro.state_desc + ' on ' + iro.db_schema_table_index + + iro.state_desc + N' on ' + iro.db_schema_table_index + CASE iro.state WHEN 0 THEN - ' at MAXDOP ' + CONVERT(NVARCHAR(30), iro.last_max_dop_used) + - '. First started ' + CONVERT(NVARCHAR(50), iro.start_time, 120) + '. ' + - CONVERT(NVARCHAR(6), CONVERT(MONEY, iro.percent_complete)) + '% complete after ' + + N' at MAXDOP ' + CONVERT(NVARCHAR(30), iro.last_max_dop_used) + + N'. First started ' + CONVERT(NVARCHAR(50), iro.start_time, 120) + N'. ' + + CONVERT(NVARCHAR(6), CONVERT(MONEY, iro.percent_complete)) + N'% complete after ' + CONVERT(NVARCHAR(30), iro.total_execution_time) + - ' minute(s). This blocks DDL and can pile up ghosts.' + N' minute(s). ' + + CASE WHEN @ResumableIndexesDisappearAfter > 0 + THEN N' Will be automatically removed by the database server at ' + CONVERT(NVARCHAR(50), (DATEADD(mi, @ResumableIndexesDisappearAfter, iro.last_pause_time)), 121) + N'. ' + ELSE N' Will not be automatically removed by the database server. ' + END + + N'This blocks DDL and can pile up ghosts.' WHEN 1 THEN - ' since ' + CONVERT(NVARCHAR(50), iro.last_pause_time, 120) + '. ' + - CONVERT(NVARCHAR(6), CONVERT(MONEY, iro.percent_complete)) + '% complete' + + N' since ' + CONVERT(NVARCHAR(50), iro.last_pause_time, 120) + N'. ' + + CONVERT(NVARCHAR(6), CONVERT(MONEY, iro.percent_complete)) + N'% complete' + /* At 100% completion, resumable indexes open up a transaction and go back to paused for what ought to be a moment. Updating statistics is one of the things that it can do in this false paused state. @@ -3312,11 +3328,11 @@ BEGIN It seems that any of the normal operations that happen at the very end of an index build can cause this. */ CASE WHEN iro.percent_complete > 99.9 - THEN '. It is probably still running, perhaps updating statistics.' - ELSE ' after ' + CONVERT(NVARCHAR(30), iro.total_execution_time) - + ' minute(s). This blocks DDL, fails transactions needing table-level X locks, and can pile up ghosts.' + THEN N'. It is probably still running, perhaps updating statistics.' + ELSE N' after ' + CONVERT(NVARCHAR(30), iro.total_execution_time) + + N' minute(s). This blocks DDL, fails transactions needing table-level X locks, and can pile up ghosts.' END - ELSE ' which is an undocumented resumable index state description.' + ELSE N' which is an undocumented resumable index state description.' END AS details, N'https://www.BrentOzar.com/go/resumable' AS URL, iro.more_info AS [More Info] @@ -3738,9 +3754,9 @@ BEGIN N'Resumable Index Operation Paused' AS finding, iro.[database_name] AS [Database Name], N'https://www.BrentOzar.com/go/resumable' AS URL, - iro.state_desc + ' on ' + iro.db_schema_table_index + - ' since ' + CONVERT(NVARCHAR(50), iro.last_pause_time, 120) + '. ' + - CONVERT(NVARCHAR(6), CONVERT(MONEY, iro.percent_complete)) + '% complete' + + iro.state_desc + N' on ' + iro.db_schema_table_index + + N' since ' + CONVERT(NVARCHAR(50), iro.last_pause_time, 120) + N'. ' + + CONVERT(NVARCHAR(6), CONVERT(MONEY, iro.percent_complete)) + N'% complete' + /* At 100% completion, resumable indexes open up a transaction and go back to paused for what ought to be a moment. Updating statistics is one of the things that it can do in this false paused state. @@ -3748,15 +3764,19 @@ BEGIN It seems that any of the normal operations that happen at the very end of an index build can cause this. */ CASE WHEN iro.percent_complete > 99.9 - THEN '. It is probably still running, perhaps updating statistics.' - ELSE ' after ' + CONVERT(NVARCHAR(30), iro.total_execution_time) - + ' minute(s). This blocks DDL, fails transactions needing table-level X locks, and can pile up ghosts.' + THEN N'. It is probably still running, perhaps updating statistics.' + ELSE N' after ' + CONVERT(NVARCHAR(30), iro.total_execution_time) + + N' minute(s). This blocks DDL, fails transactions needing table-level X locks, and can pile up ghosts. ' + END + + CASE WHEN @ResumableIndexesDisappearAfter > 0 + THEN N' Will be automatically removed by the database server at ' + CONVERT(NVARCHAR(50), (DATEADD(mi, @ResumableIndexesDisappearAfter, iro.last_pause_time)), 121) + N'. ' + ELSE N' Will not be automatically removed by the database server. ' END AS details, - 'Old index: ' + ISNULL(i.index_definition, 'not found. Either the index is new or you need @IncludeInactiveIndexes = 1') AS index_definition, + N'Old index: ' + ISNULL(i.index_definition, N'not found. Either the index is new or you need @IncludeInactiveIndexes = 1') AS index_definition, i.secret_columns, i.index_usage_summary, - 'New index: ' + iro.reserved_MB_pretty_print + '; Old index: ' + ISNULL(sz.index_size_summary,'not found.') AS index_size_summary, - 'New index: ' + iro.sql_text AS create_tsql, + N'New index: ' + iro.reserved_MB_pretty_print + N'; Old index: ' + ISNULL(sz.index_size_summary,'not found.') AS index_size_summary, + N'New index: ' + iro.sql_text AS create_tsql, iro.more_info FROM #IndexResumableOperations iro LEFT JOIN #IndexSanity AS i ON i.database_id = iro.database_id