diff --git a/Install-All-Scripts.sql b/Install-All-Scripts.sql index 0f935b626..135d42189 100755 --- a/Install-All-Scripts.sql +++ b/Install-All-Scripts.sql @@ -30,7 +30,7 @@ SET NOCOUNT ON; BEGIN; -SELECT @Version = '3.6', @VersionDate = '20190702'; +SELECT @Version = '3.7', @VersionDate = '20190826'; IF(@VersionCheckMode = 1) BEGIN @@ -1522,7 +1522,7 @@ SET NOCOUNT ON; BEGIN; -SELECT @Version = '3.6', @VersionDate = '20190702'; +SELECT @Version = '3.7', @VersionDate = '20190826'; IF(@VersionCheckMode = 1) BEGIN @@ -2845,7 +2845,7 @@ AS SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED; - SELECT @Version = '7.6', @VersionDate = '20190702'; + SELECT @Version = '7.7', @VersionDate = '20190826'; SET @OutputType = UPPER(@OutputType); IF(@VersionCheckMode = 1) @@ -11082,6 +11082,8 @@ IF @ProductVersionMajor >= 10 AND NOT EXISTS ( SELECT 1 THEN 'balanced power mode -- Uh... you want your CPUs to run at full speed, right?' WHEN '8c5e7fda-e8bf-4a96-9a85-a6e23a8c635c' THEN 'high performance power mode' + WHEN 'e9a42b02-d5df-448d-aa00-03f14749eb61' + THEN 'ultimate performance power mode' ELSE 'an unknown power mode.' END AS Details @@ -11814,7 +11816,7 @@ AS SET NOCOUNT ON; SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED; - SELECT @Version = '3.6', @VersionDate = '20190702'; + SELECT @Version = '3.7', @VersionDate = '20190826'; IF(@VersionCheckMode = 1) BEGIN @@ -13586,7 +13588,7 @@ BEGIN SET NOCOUNT ON; SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED; -SELECT @Version = '7.6', @VersionDate = '20190702'; +SELECT @Version = '7.7', @VersionDate = '20190826'; IF(@VersionCheckMode = 1) @@ -14105,6 +14107,7 @@ IF @MinutesBack IS NOT NULL RAISERROR(N'Creating temp tables for results and warnings.', 0, 1) WITH NOWAIT; + IF OBJECT_ID('tempdb.dbo.##BlitzCacheResults') IS NULL BEGIN CREATE TABLE ##BlitzCacheResults ( @@ -14305,7 +14308,9 @@ END; DECLARE @DurationFilter_i INT, @MinMemoryPerQuery INT, @msg NVARCHAR(4000), - @NoobSaibot BIT = 0; + @NoobSaibot BIT = 0, + @VersionShowsAirQuoteActualPlans BIT; + IF @SortOrder = 'sp_BlitzIndex' BEGIN @@ -14404,10 +14409,12 @@ IF EXISTS(SELECT * FROM sys.all_columns WHERE OBJECT_ID = OBJECT_ID('sys.dm_exec ELSE SET @VersionShowsSpills = 0; -DECLARE @VersionShowsAirQuoteActualPlans BIT; +/* This new 2019 & Azure SQL DB feature isn't working consistently, so turning it back off til Microsoft gets it ready. + See this Github issue for more details: https://github.com/BrentOzarULTD/SQL-Server-First-Responder-Kit/issues/2022 IF EXISTS(SELECT * FROM sys.all_columns WHERE OBJECT_ID = OBJECT_ID('sys.dm_exec_query_plan_stats') AND name = 'query_plan') SET @VersionShowsAirQuoteActualPlans = 1; ELSE +*/ SET @VersionShowsAirQuoteActualPlans = 0; IF @Reanalyze = 1 AND OBJECT_ID('tempdb..##BlitzCacheResults') IS NULL @@ -14510,6 +14517,9 @@ IF OBJECT_ID('tempdb..#missing_index_pretty') IS NOT NULL IF OBJECT_ID('tempdb..#index_spool_ugly') IS NOT NULL DROP TABLE #index_spool_ugly; + +IF OBJECT_ID('tempdb..#ReadableDBs') IS NOT NULL + DROP TABLE #ReadableDBs; CREATE TABLE #only_query_hashes ( query_hash BINARY(8) @@ -14788,6 +14798,18 @@ CREATE TABLE #index_spool_ugly ); +CREATE TABLE #ReadableDBs +( +database_id INT +); + +IF EXISTS (SELECT * FROM sys.all_objects o WHERE o.name = 'dm_hadr_database_replica_states') +BEGIN + RAISERROR('Checking for Read intent databases to exclude',0,0) WITH NOWAIT; + + EXEC('INSERT INTO #ReadableDBs (database_id) SELECT DBs.database_id FROM sys.databases DBs INNER JOIN sys.availability_replicas Replicas ON DBs.replica_id = Replicas.replica_id WHERE replica_server_name NOT IN (SELECT DISTINCT primary_replica FROM sys.dm_hadr_availability_group_states States) AND Replicas.secondary_role_allow_connections_desc = ''READ_ONLY'' AND replica_server_name = @@SERVERNAME;'); +END + RAISERROR(N'Checking plan cache age', 0, 1) WITH NOWAIT; WITH x AS ( SELECT SUM(CASE WHEN DATEDIFF(HOUR, deqs.creation_time, SYSDATETIME()) <= 24 THEN 1 ELSE 0 END) AS [plans_24], @@ -15117,10 +15139,10 @@ IF @VersionShowsAirQuoteActualPlans = 1 SET @body += N' WHERE 1 = 1 ' + @nl ; -IF EXISTS (SELECT * FROM sys.all_objects o INNER JOIN sys.all_columns c ON o.object_id = c.object_id WHERE o.name = 'dm_hadr_database_replica_states' AND c.name = 'is_primary_replica') + IF EXISTS (SELECT * FROM sys.all_objects o WHERE o.name = 'dm_hadr_database_replica_states') BEGIN RAISERROR(N'Ignoring readable secondaries databases by default', 0, 1) WITH NOWAIT; - SET @body += N' AND CAST(xpa.value AS INT) NOT IN (select database_id from sys.dm_hadr_database_replica_states where is_primary_replica = 0 AND DATABASEPROPERTYEX(DB_NAME(database_id), ''Updateability'') = ''READ_ONLY'')' + @nl ; + SET @body += N' AND CAST(xpa.value AS INT) NOT IN (SELECT database_id FROM #ReadableDBs)' + @nl ; END IF @IgnoreSystemDBs = 1 @@ -17753,8 +17775,8 @@ SELECT DISTINCT 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 (' + CONVERT(VARCHAR(10), (SELECT SUM(b2.missing_index_count) FROM ##BlitzCacheProcs AS b2 WHERE b2.SqlHandle = b.SqlHandle AND b2.QueryHash IS NOT NULL) ) + ')' ELSE '' END + - CASE WHEN unmatched_index_count > 0 THEN ', Unmatched Indexes (' + CONVERT(VARCHAR(10), (SELECT SUM(b2.unmatched_index_count) FROM ##BlitzCacheProcs AS b2 WHERE b2.SqlHandle = b.SqlHandle AND b2.QueryHash IS NOT NULL) ) + ')' ELSE '' END + + CASE WHEN missing_index_count > 0 THEN ', Missing Indexes (' + CONVERT(VARCHAR(10), (SELECT SUM(b2.missing_index_count) FROM ##BlitzCacheProcs AS b2 WHERE b2.SqlHandle = b.SqlHandle AND b2.QueryHash IS NOT NULL AND SPID = @@SPID) ) + ')' ELSE '' END + + CASE WHEN unmatched_index_count > 0 THEN ', Unmatched Indexes (' + CONVERT(VARCHAR(10), (SELECT SUM(b2.unmatched_index_count) FROM ##BlitzCacheProcs AS b2 WHERE b2.SqlHandle = b.SqlHandle AND b2.QueryHash IS NOT NULL AND SPID = @@SPID) ) + ')' ELSE '' END + CASE WHEN is_cursor = 1 THEN ', Cursor' + CASE WHEN is_optimistic_cursor = 1 THEN '; optimistic' ELSE '' END + CASE WHEN is_forward_only_cursor = 0 THEN '; not forward only' ELSE '' END @@ -17777,8 +17799,8 @@ SELECT DISTINCT CASE WHEN is_remote_query_expensive = 1 THEN ', Expensive Remote Query' ELSE '' END + CASE WHEN trace_flags_session IS NOT NULL THEN ', Session Level Trace Flag(s) Enabled: ' + trace_flags_session ELSE '' END + CASE WHEN is_unused_grant = 1 THEN ', Unused Memory Grant' ELSE '' END + - CASE WHEN function_count > 0 THEN ', Calls ' + CONVERT(VARCHAR(10), (SELECT SUM(b2.function_count) FROM ##BlitzCacheProcs AS b2 WHERE b2.SqlHandle = b.SqlHandle AND b2.QueryHash IS NOT NULL) ) + ' function(s)' ELSE '' END + - CASE WHEN clr_function_count > 0 THEN ', Calls ' + CONVERT(VARCHAR(10), (SELECT SUM(b2.clr_function_count) FROM ##BlitzCacheProcs AS b2 WHERE b2.SqlHandle = b.SqlHandle AND b2.QueryHash IS NOT NULL) ) + ' CLR function(s)' ELSE '' END + + CASE WHEN function_count > 0 THEN ', Calls ' + CONVERT(VARCHAR(10), (SELECT SUM(b2.function_count) FROM ##BlitzCacheProcs AS b2 WHERE b2.SqlHandle = b.SqlHandle AND b2.QueryHash IS NOT NULL AND SPID = @@SPID) ) + ' function(s)' ELSE '' END + + CASE WHEN clr_function_count > 0 THEN ', Calls ' + CONVERT(VARCHAR(10), (SELECT SUM(b2.clr_function_count) FROM ##BlitzCacheProcs AS b2 WHERE b2.SqlHandle = b.SqlHandle AND b2.QueryHash IS NOT NULL AND SPID = @@SPID) ) + ' CLR function(s)' ELSE '' END + CASE WHEN PlanCreationTimeHours <= 4 THEN ', Plan created last 4hrs' ELSE '' END + CASE WHEN is_table_variable = 1 THEN ', Table Variables' ELSE '' END + CASE WHEN no_stats_warning = 1 THEN ', Columns With No Statistics' ELSE '' END + @@ -19092,7 +19114,7 @@ BEGIN INSERT INTO ##BlitzCacheResults (SPID, CheckID, Priority, FindingsGroup, Finding, URL, Details) SELECT SPID, 999, - 254, + CASE WHEN ISNULL(p.percent_24, 0) > 75 THEN 1 ELSE 254 END AS Priority, 'Plan Cache Information', 'You have ' + CONVERT(NVARCHAR(10), ISNULL(p.total_plans, 0)) + ' total plans in your cache, with ' @@ -19973,7 +19995,7 @@ BEGIN SET NOCOUNT ON; SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED; -SELECT @Version = '7.6', @VersionDate = '20190702'; +SELECT @Version = '7.7', @VersionDate = '20190826'; IF(@VersionCheckMode = 1) BEGIN @@ -20225,6 +20247,7 @@ BEGIN a tool that relies on the output of sp_BlitzFirst. */ + IF OBJECT_ID('tempdb..#BlitzFirstResults') IS NOT NULL DROP TABLE #BlitzFirstResults; CREATE TABLE #BlitzFirstResults @@ -20928,6 +20951,21 @@ BEGIN END; END; + IF OBJECT_ID('tempdb..#ReadableDBs') IS NOT NULL + DROP TABLE #ReadableDBs; + CREATE TABLE #ReadableDBs ( + database_id INT + ); + + IF EXISTS (SELECT * FROM sys.all_objects o WHERE o.name = 'dm_hadr_database_replica_states') + BEGIN + RAISERROR('Checking for Read intent databases to exclude',0,0) WITH NOWAIT; + + SET @StringToExecute = 'INSERT INTO #ReadableDBs (database_id) SELECT DBs.database_id FROM sys.databases DBs INNER JOIN sys.availability_replicas Replicas ON DBs.replica_id = Replicas.replica_id WHERE replica_server_name NOT IN (SELECT DISTINCT primary_replica FROM sys.dm_hadr_availability_group_states States) AND Replicas.secondary_role_allow_connections_desc = ''READ_ONLY'' AND replica_server_name = @@SERVERNAME;'; + EXEC(@StringToExecute); + + END + SET @StockWarningHeader = ' 0 AND CAST(SERVERPROPERTY('edition') AS VARCHAR(100)) <> 'SQL Azure' @@ -21282,7 +21321,9 @@ BEGIN CROSS APPLY sys.dm_exec_query_plan(r.plan_handle) pl CROSS APPLY sys.dm_exec_sql_text(r.sql_handle) AS t WHERE r.command LIKE 'DBCC%' - AND CAST(t.text AS NVARCHAR(4000)) NOT LIKE '%dm_db_index_physical_stats%'; + AND CAST(t.text AS NVARCHAR(4000)) NOT LIKE '%dm_db_index_physical_stats%' + AND CAST(t.text AS NVARCHAR(4000)) NOT LIKE '%ALTER INDEX%' + AND r.database_id NOT IN (SELECT database_id FROM #ReadableDBs); /* Maintenance Tasks Running - Restore Running - CheckID 3 */ @@ -21315,7 +21356,8 @@ BEGIN AND request_status = N'GRANT') AS db ON s.session_id = db.request_session_id CROSS APPLY sys.dm_exec_query_plan(r.plan_handle) pl WHERE r.command LIKE 'RESTORE%' - AND s.program_name <> 'SQL Server Log Shipping'; + AND s.program_name <> 'SQL Server Log Shipping' + AND r.database_id NOT IN (SELECT database_id FROM #ReadableDBs); /* SQL Server Internal Maintenance - Database File Growing - CheckID 4 */ @@ -21342,7 +21384,8 @@ BEGIN INNER JOIN sys.dm_exec_requests r ON t.session_id = r.session_id INNER JOIN sys.dm_exec_sessions s ON r.session_id = s.session_id CROSS APPLY sys.dm_exec_query_plan(r.plan_handle) pl - WHERE t.wait_type = 'PREEMPTIVE_OS_WRITEFILEGATHER'; + WHERE t.wait_type = 'PREEMPTIVE_OS_WRITEFILEGATHER' + AND r.database_id NOT IN (SELECT database_id FROM #ReadableDBs); /* Query Problems - Long-Running Query Blocking Others - CheckID 5 */ @@ -21377,10 +21420,11 @@ BEGIN INNER JOIN sys.dm_exec_connections c ON s.session_id = c.session_id WHERE tBlocked.wait_type LIKE ''LCK%'' AND tBlocked.wait_duration_ms > 30000 /* And the blocking session ID is not blocked by anyone else: */ - AND NOT EXISTS(SELECT * FROM sys.dm_os_waiting_tasks tBlocking WHERE s.session_id = tBlocking.session_id AND tBlocking.session_id <> tBlocking.blocking_session_id AND tBlocking.blocking_session_id IS NOT NULL);'; + AND NOT EXISTS(SELECT * FROM sys.dm_os_waiting_tasks tBlocking WHERE s.session_id = tBlocking.session_id AND tBlocking.session_id <> tBlocking.blocking_session_id AND tBlocking.blocking_session_id IS NOT NULL) + AND r.database_id NOT IN (SELECT database_id FROM #ReadableDBs);'; EXECUTE sp_executesql @StringToExecute; END; - + /* Query Problems - Plan Cache Erased Recently */ IF DATEADD(mi, -15, SYSDATETIME()) < (SELECT TOP 1 creation_time FROM sys.dm_exec_query_stats ORDER BY creation_time) BEGIN @@ -21605,7 +21649,7 @@ If one of them is a lead blocker, consider killing that query.'' AS HowToStopit, /* Server Info - Memory Grant/Workspace info - CheckID 40 */ DECLARE @MaxWorkspace BIGINT - SET @MaxWorkspace = (SELECT CAST(cntr_value AS INT)/1024 FROM #PerfmonStats WHERE counter_name = N'Maximum Workspace Memory (KB)') + SET @MaxWorkspace = (SELECT CAST(cntr_value AS BIGINT)/1024 FROM #PerfmonStats WHERE counter_name = N'Maximum Workspace Memory (KB)') IF (@MaxWorkspace IS NULL OR @MaxWorkspace = 0) @@ -23934,7 +23978,7 @@ AS SET NOCOUNT ON; SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED; -SELECT @Version = '7.6', @VersionDate = '20190702'; +SELECT @Version = '7.7', @VersionDate = '20190826'; SET @OutputType = UPPER(@OutputType); IF(@VersionCheckMode = 1) @@ -24021,7 +24065,9 @@ SELECT @SQLServerProductVersion = CAST(SERVERPROPERTY('ProductVersion') AS NVARC 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); -SET @IgnoreDatabases = LTRIM(RTRIM(@IgnoreDatabases)); +SET @IgnoreDatabases = REPLACE(REPLACE(LTRIM(RTRIM(@IgnoreDatabases)), CHAR(10), ''), CHAR(13), ''); + + RAISERROR(N'Starting run. %s', 0,1, @ScriptVersionName) WITH NOWAIT; @@ -24652,7 +24698,7 @@ IF @GetAllDatabases = 1 SET @DatabaseToIgnore = SUBSTRING(@IgnoreDatabases, 0, PATINDEX('%,%',@IgnoreDatabases)) ; INSERT INTO #Ignore_Databases (DatabaseName, Reason) - SELECT @DatabaseToIgnore, 'Specified in the @IgnoreDatabases parameter' + SELECT LTRIM(RTRIM(@DatabaseToIgnore)), 'Specified in the @IgnoreDatabases parameter' OPTION (RECOMPILE) ; SET @IgnoreDatabases = SUBSTRING(@IgnoreDatabases, LEN(@DatabaseToIgnore + ',') + 1, LEN(@IgnoreDatabases)) ; @@ -24663,7 +24709,7 @@ IF @GetAllDatabases = 1 SET @IgnoreDatabases = NULL ; INSERT INTO #Ignore_Databases (DatabaseName, Reason) - SELECT @DatabaseToIgnore, 'Specified in the @IgnoreDatabases parameter' + SELECT LTRIM(RTRIM(@DatabaseToIgnore)), 'Specified in the @IgnoreDatabases parameter' OPTION (RECOMPILE) ; END; END; @@ -28643,7 +28689,7 @@ BEGIN; CASE WHEN index_id IN ( 1, 0 ) THEN ''TABLE'' ELSE ''NonClustered'' END AS [Object Type], - index_definition AS [Definition: [Property]] ColumnName {datatype maxbytes}], + LEFT(index_definition,4000) 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], @@ -28927,7 +28973,7 @@ BEGIN SET NOCOUNT ON; SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED; -SELECT @Version = '2.6', @VersionDate = '20190702'; +SELECT @Version = '2.7', @VersionDate = '20190826'; IF(@VersionCheckMode = 1) @@ -30195,7 +30241,7 @@ BEGIN /*First BEGIN*/ SET NOCOUNT ON; SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED; -SELECT @Version = '3.6', @VersionDate = '20190702'; +SELECT @Version = '3.7', @VersionDate = '20190826'; IF(@VersionCheckMode = 1) BEGIN RETURN; @@ -35920,7 +35966,7 @@ BEGIN SET NOCOUNT ON; SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED; - SELECT @Version = '7.6', @VersionDate = '20190702'; + SELECT @Version = '7.7', @VersionDate = '20190826'; IF(@VersionCheckMode = 1) BEGIN @@ -36795,6 +36841,7 @@ ALTER PROCEDURE [dbo].[sp_DatabaseRestore] @StopAt NVARCHAR(14) = NULL, @OnlyLogsAfter NVARCHAR(14) = NULL, @SimpleFolderEnumeration BIT = 0, + @DatabaseOwner SYSNAME = NULL, @Execute CHAR(1) = Y, @Debug INT = 0, @Help BIT = 0, @@ -36806,7 +36853,7 @@ SET NOCOUNT ON; /*Versioning details*/ -SELECT @Version = '7.6', @VersionDate = '20190702'; +SELECT @Version = '7.7', @VersionDate = '20190826'; IF(@VersionCheckMode = 1) BEGIN @@ -37091,62 +37138,97 @@ CREATE TABLE #Headers Correct paths in case people forget a final "\" */ /*Full*/ -IF (SELECT RIGHT(@BackupPathFull, 1)) <> '\' --Has to end in a '\' +IF (SELECT RIGHT(@BackupPathFull, 1)) <> '\' AND CHARINDEX('\', @BackupPathFull) > 0 --Has to end in a '\' BEGIN IF @Execute = 'Y' OR @Debug = 1 RAISERROR('Fixing @BackupPathFull to add a "\"', 0, 1) WITH NOWAIT; SET @BackupPathFull += N'\'; END; +ELSE IF (SELECT RIGHT(@BackupPathFull, 1)) <> '/' AND CHARINDEX('/', @BackupPathFull) > 0 --Has to end in a '/' +BEGIN + IF @Execute = 'Y' OR @Debug = 1 RAISERROR('Fixing @BackupPathFull to add a "/"', 0, 1) WITH NOWAIT; + SET @BackupPathFull += N'/'; +END; /*Diff*/ -IF (SELECT RIGHT(@BackupPathDiff, 1)) <> '\' --Has to end in a '\' +IF (SELECT RIGHT(@BackupPathDiff, 1)) <> '\' AND CHARINDEX('\', @BackupPathDiff) > 0 --Has to end in a '\' BEGIN IF @Execute = 'Y' OR @Debug = 1 RAISERROR('Fixing @BackupPathDiff to add a "\"', 0, 1) WITH NOWAIT; SET @BackupPathDiff += N'\'; END; +ELSE IF (SELECT RIGHT(@BackupPathDiff, 1)) <> '/' AND CHARINDEX('/', @BackupPathDiff) > 0 --Has to end in a '/' +BEGIN + IF @Execute = 'Y' OR @Debug = 1 RAISERROR('Fixing @BackupPathDiff to add a "/"', 0, 1) WITH NOWAIT; + SET @BackupPathDiff += N'/'; +END; /*Log*/ -IF (SELECT RIGHT(@BackupPathLog, 1)) <> '\' --Has to end in a '\' +IF (SELECT RIGHT(@BackupPathLog, 1)) <> '\' AND CHARINDEX('\', @BackupPathLog) > 0 --Has to end in a '\' BEGIN IF @Execute = 'Y' OR @Debug = 1 RAISERROR('Fixing @BackupPathLog to add a "\"', 0, 1) WITH NOWAIT; SET @BackupPathLog += N'\'; END; +ELSE IF (SELECT RIGHT(@BackupPathLog, 1)) <> '/' AND CHARINDEX('/', @BackupPathLog) > 0 --Has to end in a '/' +BEGIN + IF @Execute = 'Y' OR @Debug = 1 RAISERROR('Fixing @BackupPathLog to add a "/"', 0, 1) WITH NOWAIT; + SET @BackupPathLog += N'/'; +END; /*Move Data File*/ IF NULLIF(@MoveDataDrive, '') IS NULL BEGIN IF @Execute = 'Y' OR @Debug = 1 RAISERROR('Getting default data drive for @MoveDataDrive', 0, 1) WITH NOWAIT; SET @MoveDataDrive = CAST(SERVERPROPERTY('InstanceDefaultDataPath') AS nvarchar(260)); END; -IF (SELECT RIGHT(@MoveDataDrive, 1)) <> '\' --Has to end in a '\' +IF (SELECT RIGHT(@MoveDataDrive, 1)) <> '\' AND CHARINDEX('\', @MoveDataDrive) > 0 --Has to end in a '\' BEGIN IF @Execute = 'Y' OR @Debug = 1 RAISERROR('Fixing @MoveDataDrive to add a "\"', 0, 1) WITH NOWAIT; SET @MoveDataDrive += N'\'; END; +ELSE IF (SELECT RIGHT(@MoveDataDrive, 1)) <> '/' AND CHARINDEX('/', @MoveDataDrive) > 0 --Has to end in a '/' +BEGIN + IF @Execute = 'Y' OR @Debug = 1 RAISERROR('Fixing @MoveDataDrive to add a "/"', 0, 1) WITH NOWAIT; + SET @MoveDataDrive += N'/'; +END; /*Move Log File*/ IF NULLIF(@MoveLogDrive, '') IS NULL BEGIN IF @Execute = 'Y' OR @Debug = 1 RAISERROR('Getting default log drive for @MoveLogDrive', 0, 1) WITH NOWAIT; SET @MoveLogDrive = CAST(SERVERPROPERTY('InstanceDefaultLogPath') AS nvarchar(260)); END; -IF (SELECT RIGHT(@MoveLogDrive, 1)) <> '\' --Has to end in a '\' +IF (SELECT RIGHT(@MoveLogDrive, 1)) <> '\' AND CHARINDEX('\', @MoveLogDrive) > 0 --Has to end in a '\' BEGIN - IF @Execute = 'Y' OR @Debug = 1 RAISERROR('Fixing @MoveDataDrive to add a "\"', 0, 1) WITH NOWAIT; + IF @Execute = 'Y' OR @Debug = 1 RAISERROR('Fixing @MoveLogDrive to add a "\"', 0, 1) WITH NOWAIT; SET @MoveLogDrive += N'\'; END; +ELSE IF (SELECT RIGHT(@MoveLogDrive, 1)) <> '/' AND CHARINDEX('/', @MoveLogDrive) > 0 --Has to end in a '/' +BEGIN + IF @Execute = 'Y' OR @Debug = 1 RAISERROR('Fixing@MoveLogDrive to add a "/"', 0, 1) WITH NOWAIT; + SET @MoveLogDrive += N'/'; +END; /*Move Filestream File*/ IF NULLIF(@MoveFilestreamDrive, '') IS NULL BEGIN IF @Execute = 'Y' OR @Debug = 1 RAISERROR('Setting default data drive for @MoveFilestreamDrive', 0, 1) WITH NOWAIT; SET @MoveFilestreamDrive = CAST(SERVERPROPERTY('InstanceDefaultDataPath') AS nvarchar(260)); END; -IF (SELECT RIGHT(@MoveFilestreamDrive, 1)) <> '\' --Has to end in a '\' +IF (SELECT RIGHT(@MoveFilestreamDrive, 1)) <> '\' AND CHARINDEX('\', @MoveFilestreamDrive) > 0 --Has to end in a '\' BEGIN IF @Execute = 'Y' OR @Debug = 1 RAISERROR('Fixing @MoveFilestreamDrive to add a "\"', 0, 1) WITH NOWAIT; SET @MoveFilestreamDrive += N'\'; END; +ELSE IF (SELECT RIGHT(@MoveFilestreamDrive, 1)) <> '/' AND CHARINDEX('/', @MoveFilestreamDrive) > 0 --Has to end in a '/' +BEGIN + IF @Execute = 'Y' OR @Debug = 1 RAISERROR('Fixing @MoveFilestreamDrive to add a "/"', 0, 1) WITH NOWAIT; + SET @MoveFilestreamDrive += N'/'; +END; /*Standby Undo File*/ -IF (SELECT RIGHT(@StandbyUndoPath, 1)) <> '\' --Has to end in a '\' +IF (SELECT RIGHT(@StandbyUndoPath, 1)) <> '\' AND CHARINDEX('\', @StandbyUndoPath) > 0 --Has to end in a '\' BEGIN IF @Execute = 'Y' OR @Debug = 1 RAISERROR('Fixing @StandbyUndoPath to add a "\"', 0, 1) WITH NOWAIT; SET @StandbyUndoPath += N'\'; END; +ELSE IF (SELECT RIGHT(@StandbyUndoPath, 1)) <> '/' AND CHARINDEX('/', @StandbyUndoPath) > 0 --Has to end in a '/' +BEGIN + IF @Execute = 'Y' OR @Debug = 1 RAISERROR('Fixing @StandbyUndoPath to add a "/"', 0, 1) WITH NOWAIT; + SET @StandbyUndoPath += N'/'; +END; IF @RestoreDatabaseName IS NULL BEGIN SET @RestoreDatabaseName = @Database; @@ -37885,6 +37967,28 @@ IF @RunCheckDB = 1 EXECUTE @sql = [dbo].[CommandExecute] @Command = @sql, @CommandType = 'INTEGRITY CHECK', @Mode = 1, @DatabaseName = @Database, @LogToTable = 'Y', @Execute = 'Y'; END; + +IF @DatabaseOwner IS NOT NULL + BEGIN + IF EXISTS (SELECT * FROM master.dbo.syslogins WHERE syslogins.loginname = @DatabaseOwner) + BEGIN + SET @sql = N'ALTER AUTHORIZATION ON DATABASE::' + @RestoreDatabaseName + ' TO [' + @DatabaseOwner + ']'; + + IF @Debug = 1 OR @Execute = 'N' + BEGIN + IF @sql IS NULL PRINT '@sql is NULL for Set Database Owner'; + PRINT @sql; + END; + + IF @Debug IN (0, 1) AND @Execute = 'Y' + EXECUTE (@sql); + END + ELSE + BEGIN + PRINT @DatabaseOwner + ' is not a valid Login. Database Owner not set.' + END + END; + -- If test restore then blow the database away (be careful) IF @TestRestore = 1 BEGIN @@ -37937,7 +38041,7 @@ ALTER PROCEDURE dbo.sp_foreachdb AS BEGIN SET NOCOUNT ON; - SELECT @Version = '3.6', @VersionDate = '20190702'; + SELECT @Version = '3.7', @VersionDate = '20190826'; IF(@VersionCheckMode = 1) BEGIN @@ -38222,7 +38326,7 @@ AS BEGIN SET NOCOUNT ON; - SELECT @Version = '2.6', @VersionDate = '20190702'; + SELECT @Version = '2.7', @VersionDate = '20190826'; IF(@VersionCheckMode = 1) BEGIN diff --git a/Install-Core-Blitz-No-Query-Store.sql b/Install-Core-Blitz-No-Query-Store.sql index bf9069969..1eed2e4c6 100755 --- a/Install-Core-Blitz-No-Query-Store.sql +++ b/Install-Core-Blitz-No-Query-Store.sql @@ -36,7 +36,7 @@ AS SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED; - SELECT @Version = '7.6', @VersionDate = '20190702'; + SELECT @Version = '7.7', @VersionDate = '20190826'; SET @OutputType = UPPER(@OutputType); IF(@VersionCheckMode = 1) @@ -8273,6 +8273,8 @@ IF @ProductVersionMajor >= 10 AND NOT EXISTS ( SELECT 1 THEN 'balanced power mode -- Uh... you want your CPUs to run at full speed, right?' WHEN '8c5e7fda-e8bf-4a96-9a85-a6e23a8c635c' THEN 'high performance power mode' + WHEN 'e9a42b02-d5df-448d-aa00-03f14749eb61' + THEN 'ultimate performance power mode' ELSE 'an unknown power mode.' END AS Details @@ -9005,7 +9007,7 @@ AS SET NOCOUNT ON; SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED; - SELECT @Version = '3.6', @VersionDate = '20190702'; + SELECT @Version = '3.7', @VersionDate = '20190826'; IF(@VersionCheckMode = 1) BEGIN @@ -10777,7 +10779,7 @@ BEGIN SET NOCOUNT ON; SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED; -SELECT @Version = '7.6', @VersionDate = '20190702'; +SELECT @Version = '7.7', @VersionDate = '20190826'; IF(@VersionCheckMode = 1) @@ -11296,6 +11298,7 @@ IF @MinutesBack IS NOT NULL RAISERROR(N'Creating temp tables for results and warnings.', 0, 1) WITH NOWAIT; + IF OBJECT_ID('tempdb.dbo.##BlitzCacheResults') IS NULL BEGIN CREATE TABLE ##BlitzCacheResults ( @@ -11496,7 +11499,9 @@ END; DECLARE @DurationFilter_i INT, @MinMemoryPerQuery INT, @msg NVARCHAR(4000), - @NoobSaibot BIT = 0; + @NoobSaibot BIT = 0, + @VersionShowsAirQuoteActualPlans BIT; + IF @SortOrder = 'sp_BlitzIndex' BEGIN @@ -11595,10 +11600,12 @@ IF EXISTS(SELECT * FROM sys.all_columns WHERE OBJECT_ID = OBJECT_ID('sys.dm_exec ELSE SET @VersionShowsSpills = 0; -DECLARE @VersionShowsAirQuoteActualPlans BIT; +/* This new 2019 & Azure SQL DB feature isn't working consistently, so turning it back off til Microsoft gets it ready. + See this Github issue for more details: https://github.com/BrentOzarULTD/SQL-Server-First-Responder-Kit/issues/2022 IF EXISTS(SELECT * FROM sys.all_columns WHERE OBJECT_ID = OBJECT_ID('sys.dm_exec_query_plan_stats') AND name = 'query_plan') SET @VersionShowsAirQuoteActualPlans = 1; ELSE +*/ SET @VersionShowsAirQuoteActualPlans = 0; IF @Reanalyze = 1 AND OBJECT_ID('tempdb..##BlitzCacheResults') IS NULL @@ -11701,6 +11708,9 @@ IF OBJECT_ID('tempdb..#missing_index_pretty') IS NOT NULL IF OBJECT_ID('tempdb..#index_spool_ugly') IS NOT NULL DROP TABLE #index_spool_ugly; + +IF OBJECT_ID('tempdb..#ReadableDBs') IS NOT NULL + DROP TABLE #ReadableDBs; CREATE TABLE #only_query_hashes ( query_hash BINARY(8) @@ -11979,6 +11989,18 @@ CREATE TABLE #index_spool_ugly ); +CREATE TABLE #ReadableDBs +( +database_id INT +); + +IF EXISTS (SELECT * FROM sys.all_objects o WHERE o.name = 'dm_hadr_database_replica_states') +BEGIN + RAISERROR('Checking for Read intent databases to exclude',0,0) WITH NOWAIT; + + EXEC('INSERT INTO #ReadableDBs (database_id) SELECT DBs.database_id FROM sys.databases DBs INNER JOIN sys.availability_replicas Replicas ON DBs.replica_id = Replicas.replica_id WHERE replica_server_name NOT IN (SELECT DISTINCT primary_replica FROM sys.dm_hadr_availability_group_states States) AND Replicas.secondary_role_allow_connections_desc = ''READ_ONLY'' AND replica_server_name = @@SERVERNAME;'); +END + RAISERROR(N'Checking plan cache age', 0, 1) WITH NOWAIT; WITH x AS ( SELECT SUM(CASE WHEN DATEDIFF(HOUR, deqs.creation_time, SYSDATETIME()) <= 24 THEN 1 ELSE 0 END) AS [plans_24], @@ -12308,10 +12330,10 @@ IF @VersionShowsAirQuoteActualPlans = 1 SET @body += N' WHERE 1 = 1 ' + @nl ; -IF EXISTS (SELECT * FROM sys.all_objects o INNER JOIN sys.all_columns c ON o.object_id = c.object_id WHERE o.name = 'dm_hadr_database_replica_states' AND c.name = 'is_primary_replica') + IF EXISTS (SELECT * FROM sys.all_objects o WHERE o.name = 'dm_hadr_database_replica_states') BEGIN RAISERROR(N'Ignoring readable secondaries databases by default', 0, 1) WITH NOWAIT; - SET @body += N' AND CAST(xpa.value AS INT) NOT IN (select database_id from sys.dm_hadr_database_replica_states where is_primary_replica = 0 AND DATABASEPROPERTYEX(DB_NAME(database_id), ''Updateability'') = ''READ_ONLY'')' + @nl ; + SET @body += N' AND CAST(xpa.value AS INT) NOT IN (SELECT database_id FROM #ReadableDBs)' + @nl ; END IF @IgnoreSystemDBs = 1 @@ -14944,8 +14966,8 @@ SELECT DISTINCT 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 (' + CONVERT(VARCHAR(10), (SELECT SUM(b2.missing_index_count) FROM ##BlitzCacheProcs AS b2 WHERE b2.SqlHandle = b.SqlHandle AND b2.QueryHash IS NOT NULL) ) + ')' ELSE '' END + - CASE WHEN unmatched_index_count > 0 THEN ', Unmatched Indexes (' + CONVERT(VARCHAR(10), (SELECT SUM(b2.unmatched_index_count) FROM ##BlitzCacheProcs AS b2 WHERE b2.SqlHandle = b.SqlHandle AND b2.QueryHash IS NOT NULL) ) + ')' ELSE '' END + + CASE WHEN missing_index_count > 0 THEN ', Missing Indexes (' + CONVERT(VARCHAR(10), (SELECT SUM(b2.missing_index_count) FROM ##BlitzCacheProcs AS b2 WHERE b2.SqlHandle = b.SqlHandle AND b2.QueryHash IS NOT NULL AND SPID = @@SPID) ) + ')' ELSE '' END + + CASE WHEN unmatched_index_count > 0 THEN ', Unmatched Indexes (' + CONVERT(VARCHAR(10), (SELECT SUM(b2.unmatched_index_count) FROM ##BlitzCacheProcs AS b2 WHERE b2.SqlHandle = b.SqlHandle AND b2.QueryHash IS NOT NULL AND SPID = @@SPID) ) + ')' ELSE '' END + CASE WHEN is_cursor = 1 THEN ', Cursor' + CASE WHEN is_optimistic_cursor = 1 THEN '; optimistic' ELSE '' END + CASE WHEN is_forward_only_cursor = 0 THEN '; not forward only' ELSE '' END @@ -14968,8 +14990,8 @@ SELECT DISTINCT CASE WHEN is_remote_query_expensive = 1 THEN ', Expensive Remote Query' ELSE '' END + CASE WHEN trace_flags_session IS NOT NULL THEN ', Session Level Trace Flag(s) Enabled: ' + trace_flags_session ELSE '' END + CASE WHEN is_unused_grant = 1 THEN ', Unused Memory Grant' ELSE '' END + - CASE WHEN function_count > 0 THEN ', Calls ' + CONVERT(VARCHAR(10), (SELECT SUM(b2.function_count) FROM ##BlitzCacheProcs AS b2 WHERE b2.SqlHandle = b.SqlHandle AND b2.QueryHash IS NOT NULL) ) + ' function(s)' ELSE '' END + - CASE WHEN clr_function_count > 0 THEN ', Calls ' + CONVERT(VARCHAR(10), (SELECT SUM(b2.clr_function_count) FROM ##BlitzCacheProcs AS b2 WHERE b2.SqlHandle = b.SqlHandle AND b2.QueryHash IS NOT NULL) ) + ' CLR function(s)' ELSE '' END + + CASE WHEN function_count > 0 THEN ', Calls ' + CONVERT(VARCHAR(10), (SELECT SUM(b2.function_count) FROM ##BlitzCacheProcs AS b2 WHERE b2.SqlHandle = b.SqlHandle AND b2.QueryHash IS NOT NULL AND SPID = @@SPID) ) + ' function(s)' ELSE '' END + + CASE WHEN clr_function_count > 0 THEN ', Calls ' + CONVERT(VARCHAR(10), (SELECT SUM(b2.clr_function_count) FROM ##BlitzCacheProcs AS b2 WHERE b2.SqlHandle = b.SqlHandle AND b2.QueryHash IS NOT NULL AND SPID = @@SPID) ) + ' CLR function(s)' ELSE '' END + CASE WHEN PlanCreationTimeHours <= 4 THEN ', Plan created last 4hrs' ELSE '' END + CASE WHEN is_table_variable = 1 THEN ', Table Variables' ELSE '' END + CASE WHEN no_stats_warning = 1 THEN ', Columns With No Statistics' ELSE '' END + @@ -16283,7 +16305,7 @@ BEGIN INSERT INTO ##BlitzCacheResults (SPID, CheckID, Priority, FindingsGroup, Finding, URL, Details) SELECT SPID, 999, - 254, + CASE WHEN ISNULL(p.percent_24, 0) > 75 THEN 1 ELSE 254 END AS Priority, 'Plan Cache Information', 'You have ' + CONVERT(NVARCHAR(10), ISNULL(p.total_plans, 0)) + ' total plans in your cache, with ' @@ -17164,7 +17186,7 @@ BEGIN SET NOCOUNT ON; SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED; -SELECT @Version = '7.6', @VersionDate = '20190702'; +SELECT @Version = '7.7', @VersionDate = '20190826'; IF(@VersionCheckMode = 1) BEGIN @@ -17416,6 +17438,7 @@ BEGIN a tool that relies on the output of sp_BlitzFirst. */ + IF OBJECT_ID('tempdb..#BlitzFirstResults') IS NOT NULL DROP TABLE #BlitzFirstResults; CREATE TABLE #BlitzFirstResults @@ -18119,6 +18142,21 @@ BEGIN END; END; + IF OBJECT_ID('tempdb..#ReadableDBs') IS NOT NULL + DROP TABLE #ReadableDBs; + CREATE TABLE #ReadableDBs ( + database_id INT + ); + + IF EXISTS (SELECT * FROM sys.all_objects o WHERE o.name = 'dm_hadr_database_replica_states') + BEGIN + RAISERROR('Checking for Read intent databases to exclude',0,0) WITH NOWAIT; + + SET @StringToExecute = 'INSERT INTO #ReadableDBs (database_id) SELECT DBs.database_id FROM sys.databases DBs INNER JOIN sys.availability_replicas Replicas ON DBs.replica_id = Replicas.replica_id WHERE replica_server_name NOT IN (SELECT DISTINCT primary_replica FROM sys.dm_hadr_availability_group_states States) AND Replicas.secondary_role_allow_connections_desc = ''READ_ONLY'' AND replica_server_name = @@SERVERNAME;'; + EXEC(@StringToExecute); + + END + SET @StockWarningHeader = ' 0 AND CAST(SERVERPROPERTY('edition') AS VARCHAR(100)) <> 'SQL Azure' @@ -18473,7 +18512,9 @@ BEGIN CROSS APPLY sys.dm_exec_query_plan(r.plan_handle) pl CROSS APPLY sys.dm_exec_sql_text(r.sql_handle) AS t WHERE r.command LIKE 'DBCC%' - AND CAST(t.text AS NVARCHAR(4000)) NOT LIKE '%dm_db_index_physical_stats%'; + AND CAST(t.text AS NVARCHAR(4000)) NOT LIKE '%dm_db_index_physical_stats%' + AND CAST(t.text AS NVARCHAR(4000)) NOT LIKE '%ALTER INDEX%' + AND r.database_id NOT IN (SELECT database_id FROM #ReadableDBs); /* Maintenance Tasks Running - Restore Running - CheckID 3 */ @@ -18506,7 +18547,8 @@ BEGIN AND request_status = N'GRANT') AS db ON s.session_id = db.request_session_id CROSS APPLY sys.dm_exec_query_plan(r.plan_handle) pl WHERE r.command LIKE 'RESTORE%' - AND s.program_name <> 'SQL Server Log Shipping'; + AND s.program_name <> 'SQL Server Log Shipping' + AND r.database_id NOT IN (SELECT database_id FROM #ReadableDBs); /* SQL Server Internal Maintenance - Database File Growing - CheckID 4 */ @@ -18533,7 +18575,8 @@ BEGIN INNER JOIN sys.dm_exec_requests r ON t.session_id = r.session_id INNER JOIN sys.dm_exec_sessions s ON r.session_id = s.session_id CROSS APPLY sys.dm_exec_query_plan(r.plan_handle) pl - WHERE t.wait_type = 'PREEMPTIVE_OS_WRITEFILEGATHER'; + WHERE t.wait_type = 'PREEMPTIVE_OS_WRITEFILEGATHER' + AND r.database_id NOT IN (SELECT database_id FROM #ReadableDBs); /* Query Problems - Long-Running Query Blocking Others - CheckID 5 */ @@ -18568,10 +18611,11 @@ BEGIN INNER JOIN sys.dm_exec_connections c ON s.session_id = c.session_id WHERE tBlocked.wait_type LIKE ''LCK%'' AND tBlocked.wait_duration_ms > 30000 /* And the blocking session ID is not blocked by anyone else: */ - AND NOT EXISTS(SELECT * FROM sys.dm_os_waiting_tasks tBlocking WHERE s.session_id = tBlocking.session_id AND tBlocking.session_id <> tBlocking.blocking_session_id AND tBlocking.blocking_session_id IS NOT NULL);'; + AND NOT EXISTS(SELECT * FROM sys.dm_os_waiting_tasks tBlocking WHERE s.session_id = tBlocking.session_id AND tBlocking.session_id <> tBlocking.blocking_session_id AND tBlocking.blocking_session_id IS NOT NULL) + AND r.database_id NOT IN (SELECT database_id FROM #ReadableDBs);'; EXECUTE sp_executesql @StringToExecute; END; - + /* Query Problems - Plan Cache Erased Recently */ IF DATEADD(mi, -15, SYSDATETIME()) < (SELECT TOP 1 creation_time FROM sys.dm_exec_query_stats ORDER BY creation_time) BEGIN @@ -18796,7 +18840,7 @@ If one of them is a lead blocker, consider killing that query.'' AS HowToStopit, /* Server Info - Memory Grant/Workspace info - CheckID 40 */ DECLARE @MaxWorkspace BIGINT - SET @MaxWorkspace = (SELECT CAST(cntr_value AS INT)/1024 FROM #PerfmonStats WHERE counter_name = N'Maximum Workspace Memory (KB)') + SET @MaxWorkspace = (SELECT CAST(cntr_value AS BIGINT)/1024 FROM #PerfmonStats WHERE counter_name = N'Maximum Workspace Memory (KB)') IF (@MaxWorkspace IS NULL OR @MaxWorkspace = 0) @@ -21125,7 +21169,7 @@ AS SET NOCOUNT ON; SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED; -SELECT @Version = '7.6', @VersionDate = '20190702'; +SELECT @Version = '7.7', @VersionDate = '20190826'; SET @OutputType = UPPER(@OutputType); IF(@VersionCheckMode = 1) @@ -21212,7 +21256,9 @@ SELECT @SQLServerProductVersion = CAST(SERVERPROPERTY('ProductVersion') AS NVARC 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); -SET @IgnoreDatabases = LTRIM(RTRIM(@IgnoreDatabases)); +SET @IgnoreDatabases = REPLACE(REPLACE(LTRIM(RTRIM(@IgnoreDatabases)), CHAR(10), ''), CHAR(13), ''); + + RAISERROR(N'Starting run. %s', 0,1, @ScriptVersionName) WITH NOWAIT; @@ -21843,7 +21889,7 @@ IF @GetAllDatabases = 1 SET @DatabaseToIgnore = SUBSTRING(@IgnoreDatabases, 0, PATINDEX('%,%',@IgnoreDatabases)) ; INSERT INTO #Ignore_Databases (DatabaseName, Reason) - SELECT @DatabaseToIgnore, 'Specified in the @IgnoreDatabases parameter' + SELECT LTRIM(RTRIM(@DatabaseToIgnore)), 'Specified in the @IgnoreDatabases parameter' OPTION (RECOMPILE) ; SET @IgnoreDatabases = SUBSTRING(@IgnoreDatabases, LEN(@DatabaseToIgnore + ',') + 1, LEN(@IgnoreDatabases)) ; @@ -21854,7 +21900,7 @@ IF @GetAllDatabases = 1 SET @IgnoreDatabases = NULL ; INSERT INTO #Ignore_Databases (DatabaseName, Reason) - SELECT @DatabaseToIgnore, 'Specified in the @IgnoreDatabases parameter' + SELECT LTRIM(RTRIM(@DatabaseToIgnore)), 'Specified in the @IgnoreDatabases parameter' OPTION (RECOMPILE) ; END; END; @@ -25834,7 +25880,7 @@ BEGIN; CASE WHEN index_id IN ( 1, 0 ) THEN ''TABLE'' ELSE ''NonClustered'' END AS [Object Type], - index_definition AS [Definition: [Property]] ColumnName {datatype maxbytes}], + LEFT(index_definition,4000) 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], @@ -26118,7 +26164,7 @@ BEGIN SET NOCOUNT ON; SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED; -SELECT @Version = '2.6', @VersionDate = '20190702'; +SELECT @Version = '2.7', @VersionDate = '20190826'; IF(@VersionCheckMode = 1) @@ -27357,7 +27403,7 @@ BEGIN SET NOCOUNT ON; SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED; - SELECT @Version = '7.6', @VersionDate = '20190702'; + SELECT @Version = '7.7', @VersionDate = '20190826'; IF(@VersionCheckMode = 1) BEGIN diff --git a/Install-Core-Blitz-With-Query-Store.sql b/Install-Core-Blitz-With-Query-Store.sql index 88308e7cd..68d5cf9fb 100755 --- a/Install-Core-Blitz-With-Query-Store.sql +++ b/Install-Core-Blitz-With-Query-Store.sql @@ -36,7 +36,7 @@ AS SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED; - SELECT @Version = '7.6', @VersionDate = '20190702'; + SELECT @Version = '7.7', @VersionDate = '20190826'; SET @OutputType = UPPER(@OutputType); IF(@VersionCheckMode = 1) @@ -8273,6 +8273,8 @@ IF @ProductVersionMajor >= 10 AND NOT EXISTS ( SELECT 1 THEN 'balanced power mode -- Uh... you want your CPUs to run at full speed, right?' WHEN '8c5e7fda-e8bf-4a96-9a85-a6e23a8c635c' THEN 'high performance power mode' + WHEN 'e9a42b02-d5df-448d-aa00-03f14749eb61' + THEN 'ultimate performance power mode' ELSE 'an unknown power mode.' END AS Details @@ -9005,7 +9007,7 @@ AS SET NOCOUNT ON; SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED; - SELECT @Version = '3.6', @VersionDate = '20190702'; + SELECT @Version = '3.7', @VersionDate = '20190826'; IF(@VersionCheckMode = 1) BEGIN @@ -10777,7 +10779,7 @@ BEGIN SET NOCOUNT ON; SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED; -SELECT @Version = '7.6', @VersionDate = '20190702'; +SELECT @Version = '7.7', @VersionDate = '20190826'; IF(@VersionCheckMode = 1) @@ -11296,6 +11298,7 @@ IF @MinutesBack IS NOT NULL RAISERROR(N'Creating temp tables for results and warnings.', 0, 1) WITH NOWAIT; + IF OBJECT_ID('tempdb.dbo.##BlitzCacheResults') IS NULL BEGIN CREATE TABLE ##BlitzCacheResults ( @@ -11496,7 +11499,9 @@ END; DECLARE @DurationFilter_i INT, @MinMemoryPerQuery INT, @msg NVARCHAR(4000), - @NoobSaibot BIT = 0; + @NoobSaibot BIT = 0, + @VersionShowsAirQuoteActualPlans BIT; + IF @SortOrder = 'sp_BlitzIndex' BEGIN @@ -11595,10 +11600,12 @@ IF EXISTS(SELECT * FROM sys.all_columns WHERE OBJECT_ID = OBJECT_ID('sys.dm_exec ELSE SET @VersionShowsSpills = 0; -DECLARE @VersionShowsAirQuoteActualPlans BIT; +/* This new 2019 & Azure SQL DB feature isn't working consistently, so turning it back off til Microsoft gets it ready. + See this Github issue for more details: https://github.com/BrentOzarULTD/SQL-Server-First-Responder-Kit/issues/2022 IF EXISTS(SELECT * FROM sys.all_columns WHERE OBJECT_ID = OBJECT_ID('sys.dm_exec_query_plan_stats') AND name = 'query_plan') SET @VersionShowsAirQuoteActualPlans = 1; ELSE +*/ SET @VersionShowsAirQuoteActualPlans = 0; IF @Reanalyze = 1 AND OBJECT_ID('tempdb..##BlitzCacheResults') IS NULL @@ -11701,6 +11708,9 @@ IF OBJECT_ID('tempdb..#missing_index_pretty') IS NOT NULL IF OBJECT_ID('tempdb..#index_spool_ugly') IS NOT NULL DROP TABLE #index_spool_ugly; + +IF OBJECT_ID('tempdb..#ReadableDBs') IS NOT NULL + DROP TABLE #ReadableDBs; CREATE TABLE #only_query_hashes ( query_hash BINARY(8) @@ -11979,6 +11989,18 @@ CREATE TABLE #index_spool_ugly ); +CREATE TABLE #ReadableDBs +( +database_id INT +); + +IF EXISTS (SELECT * FROM sys.all_objects o WHERE o.name = 'dm_hadr_database_replica_states') +BEGIN + RAISERROR('Checking for Read intent databases to exclude',0,0) WITH NOWAIT; + + EXEC('INSERT INTO #ReadableDBs (database_id) SELECT DBs.database_id FROM sys.databases DBs INNER JOIN sys.availability_replicas Replicas ON DBs.replica_id = Replicas.replica_id WHERE replica_server_name NOT IN (SELECT DISTINCT primary_replica FROM sys.dm_hadr_availability_group_states States) AND Replicas.secondary_role_allow_connections_desc = ''READ_ONLY'' AND replica_server_name = @@SERVERNAME;'); +END + RAISERROR(N'Checking plan cache age', 0, 1) WITH NOWAIT; WITH x AS ( SELECT SUM(CASE WHEN DATEDIFF(HOUR, deqs.creation_time, SYSDATETIME()) <= 24 THEN 1 ELSE 0 END) AS [plans_24], @@ -12308,10 +12330,10 @@ IF @VersionShowsAirQuoteActualPlans = 1 SET @body += N' WHERE 1 = 1 ' + @nl ; -IF EXISTS (SELECT * FROM sys.all_objects o INNER JOIN sys.all_columns c ON o.object_id = c.object_id WHERE o.name = 'dm_hadr_database_replica_states' AND c.name = 'is_primary_replica') + IF EXISTS (SELECT * FROM sys.all_objects o WHERE o.name = 'dm_hadr_database_replica_states') BEGIN RAISERROR(N'Ignoring readable secondaries databases by default', 0, 1) WITH NOWAIT; - SET @body += N' AND CAST(xpa.value AS INT) NOT IN (select database_id from sys.dm_hadr_database_replica_states where is_primary_replica = 0 AND DATABASEPROPERTYEX(DB_NAME(database_id), ''Updateability'') = ''READ_ONLY'')' + @nl ; + SET @body += N' AND CAST(xpa.value AS INT) NOT IN (SELECT database_id FROM #ReadableDBs)' + @nl ; END IF @IgnoreSystemDBs = 1 @@ -14944,8 +14966,8 @@ SELECT DISTINCT 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 (' + CONVERT(VARCHAR(10), (SELECT SUM(b2.missing_index_count) FROM ##BlitzCacheProcs AS b2 WHERE b2.SqlHandle = b.SqlHandle AND b2.QueryHash IS NOT NULL) ) + ')' ELSE '' END + - CASE WHEN unmatched_index_count > 0 THEN ', Unmatched Indexes (' + CONVERT(VARCHAR(10), (SELECT SUM(b2.unmatched_index_count) FROM ##BlitzCacheProcs AS b2 WHERE b2.SqlHandle = b.SqlHandle AND b2.QueryHash IS NOT NULL) ) + ')' ELSE '' END + + CASE WHEN missing_index_count > 0 THEN ', Missing Indexes (' + CONVERT(VARCHAR(10), (SELECT SUM(b2.missing_index_count) FROM ##BlitzCacheProcs AS b2 WHERE b2.SqlHandle = b.SqlHandle AND b2.QueryHash IS NOT NULL AND SPID = @@SPID) ) + ')' ELSE '' END + + CASE WHEN unmatched_index_count > 0 THEN ', Unmatched Indexes (' + CONVERT(VARCHAR(10), (SELECT SUM(b2.unmatched_index_count) FROM ##BlitzCacheProcs AS b2 WHERE b2.SqlHandle = b.SqlHandle AND b2.QueryHash IS NOT NULL AND SPID = @@SPID) ) + ')' ELSE '' END + CASE WHEN is_cursor = 1 THEN ', Cursor' + CASE WHEN is_optimistic_cursor = 1 THEN '; optimistic' ELSE '' END + CASE WHEN is_forward_only_cursor = 0 THEN '; not forward only' ELSE '' END @@ -14968,8 +14990,8 @@ SELECT DISTINCT CASE WHEN is_remote_query_expensive = 1 THEN ', Expensive Remote Query' ELSE '' END + CASE WHEN trace_flags_session IS NOT NULL THEN ', Session Level Trace Flag(s) Enabled: ' + trace_flags_session ELSE '' END + CASE WHEN is_unused_grant = 1 THEN ', Unused Memory Grant' ELSE '' END + - CASE WHEN function_count > 0 THEN ', Calls ' + CONVERT(VARCHAR(10), (SELECT SUM(b2.function_count) FROM ##BlitzCacheProcs AS b2 WHERE b2.SqlHandle = b.SqlHandle AND b2.QueryHash IS NOT NULL) ) + ' function(s)' ELSE '' END + - CASE WHEN clr_function_count > 0 THEN ', Calls ' + CONVERT(VARCHAR(10), (SELECT SUM(b2.clr_function_count) FROM ##BlitzCacheProcs AS b2 WHERE b2.SqlHandle = b.SqlHandle AND b2.QueryHash IS NOT NULL) ) + ' CLR function(s)' ELSE '' END + + CASE WHEN function_count > 0 THEN ', Calls ' + CONVERT(VARCHAR(10), (SELECT SUM(b2.function_count) FROM ##BlitzCacheProcs AS b2 WHERE b2.SqlHandle = b.SqlHandle AND b2.QueryHash IS NOT NULL AND SPID = @@SPID) ) + ' function(s)' ELSE '' END + + CASE WHEN clr_function_count > 0 THEN ', Calls ' + CONVERT(VARCHAR(10), (SELECT SUM(b2.clr_function_count) FROM ##BlitzCacheProcs AS b2 WHERE b2.SqlHandle = b.SqlHandle AND b2.QueryHash IS NOT NULL AND SPID = @@SPID) ) + ' CLR function(s)' ELSE '' END + CASE WHEN PlanCreationTimeHours <= 4 THEN ', Plan created last 4hrs' ELSE '' END + CASE WHEN is_table_variable = 1 THEN ', Table Variables' ELSE '' END + CASE WHEN no_stats_warning = 1 THEN ', Columns With No Statistics' ELSE '' END + @@ -16283,7 +16305,7 @@ BEGIN INSERT INTO ##BlitzCacheResults (SPID, CheckID, Priority, FindingsGroup, Finding, URL, Details) SELECT SPID, 999, - 254, + CASE WHEN ISNULL(p.percent_24, 0) > 75 THEN 1 ELSE 254 END AS Priority, 'Plan Cache Information', 'You have ' + CONVERT(NVARCHAR(10), ISNULL(p.total_plans, 0)) + ' total plans in your cache, with ' @@ -17164,7 +17186,7 @@ BEGIN SET NOCOUNT ON; SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED; -SELECT @Version = '7.6', @VersionDate = '20190702'; +SELECT @Version = '7.7', @VersionDate = '20190826'; IF(@VersionCheckMode = 1) BEGIN @@ -17416,6 +17438,7 @@ BEGIN a tool that relies on the output of sp_BlitzFirst. */ + IF OBJECT_ID('tempdb..#BlitzFirstResults') IS NOT NULL DROP TABLE #BlitzFirstResults; CREATE TABLE #BlitzFirstResults @@ -18119,6 +18142,21 @@ BEGIN END; END; + IF OBJECT_ID('tempdb..#ReadableDBs') IS NOT NULL + DROP TABLE #ReadableDBs; + CREATE TABLE #ReadableDBs ( + database_id INT + ); + + IF EXISTS (SELECT * FROM sys.all_objects o WHERE o.name = 'dm_hadr_database_replica_states') + BEGIN + RAISERROR('Checking for Read intent databases to exclude',0,0) WITH NOWAIT; + + SET @StringToExecute = 'INSERT INTO #ReadableDBs (database_id) SELECT DBs.database_id FROM sys.databases DBs INNER JOIN sys.availability_replicas Replicas ON DBs.replica_id = Replicas.replica_id WHERE replica_server_name NOT IN (SELECT DISTINCT primary_replica FROM sys.dm_hadr_availability_group_states States) AND Replicas.secondary_role_allow_connections_desc = ''READ_ONLY'' AND replica_server_name = @@SERVERNAME;'; + EXEC(@StringToExecute); + + END + SET @StockWarningHeader = ' 0 AND CAST(SERVERPROPERTY('edition') AS VARCHAR(100)) <> 'SQL Azure' @@ -18473,7 +18512,9 @@ BEGIN CROSS APPLY sys.dm_exec_query_plan(r.plan_handle) pl CROSS APPLY sys.dm_exec_sql_text(r.sql_handle) AS t WHERE r.command LIKE 'DBCC%' - AND CAST(t.text AS NVARCHAR(4000)) NOT LIKE '%dm_db_index_physical_stats%'; + AND CAST(t.text AS NVARCHAR(4000)) NOT LIKE '%dm_db_index_physical_stats%' + AND CAST(t.text AS NVARCHAR(4000)) NOT LIKE '%ALTER INDEX%' + AND r.database_id NOT IN (SELECT database_id FROM #ReadableDBs); /* Maintenance Tasks Running - Restore Running - CheckID 3 */ @@ -18506,7 +18547,8 @@ BEGIN AND request_status = N'GRANT') AS db ON s.session_id = db.request_session_id CROSS APPLY sys.dm_exec_query_plan(r.plan_handle) pl WHERE r.command LIKE 'RESTORE%' - AND s.program_name <> 'SQL Server Log Shipping'; + AND s.program_name <> 'SQL Server Log Shipping' + AND r.database_id NOT IN (SELECT database_id FROM #ReadableDBs); /* SQL Server Internal Maintenance - Database File Growing - CheckID 4 */ @@ -18533,7 +18575,8 @@ BEGIN INNER JOIN sys.dm_exec_requests r ON t.session_id = r.session_id INNER JOIN sys.dm_exec_sessions s ON r.session_id = s.session_id CROSS APPLY sys.dm_exec_query_plan(r.plan_handle) pl - WHERE t.wait_type = 'PREEMPTIVE_OS_WRITEFILEGATHER'; + WHERE t.wait_type = 'PREEMPTIVE_OS_WRITEFILEGATHER' + AND r.database_id NOT IN (SELECT database_id FROM #ReadableDBs); /* Query Problems - Long-Running Query Blocking Others - CheckID 5 */ @@ -18568,10 +18611,11 @@ BEGIN INNER JOIN sys.dm_exec_connections c ON s.session_id = c.session_id WHERE tBlocked.wait_type LIKE ''LCK%'' AND tBlocked.wait_duration_ms > 30000 /* And the blocking session ID is not blocked by anyone else: */ - AND NOT EXISTS(SELECT * FROM sys.dm_os_waiting_tasks tBlocking WHERE s.session_id = tBlocking.session_id AND tBlocking.session_id <> tBlocking.blocking_session_id AND tBlocking.blocking_session_id IS NOT NULL);'; + AND NOT EXISTS(SELECT * FROM sys.dm_os_waiting_tasks tBlocking WHERE s.session_id = tBlocking.session_id AND tBlocking.session_id <> tBlocking.blocking_session_id AND tBlocking.blocking_session_id IS NOT NULL) + AND r.database_id NOT IN (SELECT database_id FROM #ReadableDBs);'; EXECUTE sp_executesql @StringToExecute; END; - + /* Query Problems - Plan Cache Erased Recently */ IF DATEADD(mi, -15, SYSDATETIME()) < (SELECT TOP 1 creation_time FROM sys.dm_exec_query_stats ORDER BY creation_time) BEGIN @@ -18796,7 +18840,7 @@ If one of them is a lead blocker, consider killing that query.'' AS HowToStopit, /* Server Info - Memory Grant/Workspace info - CheckID 40 */ DECLARE @MaxWorkspace BIGINT - SET @MaxWorkspace = (SELECT CAST(cntr_value AS INT)/1024 FROM #PerfmonStats WHERE counter_name = N'Maximum Workspace Memory (KB)') + SET @MaxWorkspace = (SELECT CAST(cntr_value AS BIGINT)/1024 FROM #PerfmonStats WHERE counter_name = N'Maximum Workspace Memory (KB)') IF (@MaxWorkspace IS NULL OR @MaxWorkspace = 0) @@ -21125,7 +21169,7 @@ AS SET NOCOUNT ON; SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED; -SELECT @Version = '7.6', @VersionDate = '20190702'; +SELECT @Version = '7.7', @VersionDate = '20190826'; SET @OutputType = UPPER(@OutputType); IF(@VersionCheckMode = 1) @@ -21212,7 +21256,9 @@ SELECT @SQLServerProductVersion = CAST(SERVERPROPERTY('ProductVersion') AS NVARC 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); -SET @IgnoreDatabases = LTRIM(RTRIM(@IgnoreDatabases)); +SET @IgnoreDatabases = REPLACE(REPLACE(LTRIM(RTRIM(@IgnoreDatabases)), CHAR(10), ''), CHAR(13), ''); + + RAISERROR(N'Starting run. %s', 0,1, @ScriptVersionName) WITH NOWAIT; @@ -21843,7 +21889,7 @@ IF @GetAllDatabases = 1 SET @DatabaseToIgnore = SUBSTRING(@IgnoreDatabases, 0, PATINDEX('%,%',@IgnoreDatabases)) ; INSERT INTO #Ignore_Databases (DatabaseName, Reason) - SELECT @DatabaseToIgnore, 'Specified in the @IgnoreDatabases parameter' + SELECT LTRIM(RTRIM(@DatabaseToIgnore)), 'Specified in the @IgnoreDatabases parameter' OPTION (RECOMPILE) ; SET @IgnoreDatabases = SUBSTRING(@IgnoreDatabases, LEN(@DatabaseToIgnore + ',') + 1, LEN(@IgnoreDatabases)) ; @@ -21854,7 +21900,7 @@ IF @GetAllDatabases = 1 SET @IgnoreDatabases = NULL ; INSERT INTO #Ignore_Databases (DatabaseName, Reason) - SELECT @DatabaseToIgnore, 'Specified in the @IgnoreDatabases parameter' + SELECT LTRIM(RTRIM(@DatabaseToIgnore)), 'Specified in the @IgnoreDatabases parameter' OPTION (RECOMPILE) ; END; END; @@ -25834,7 +25880,7 @@ BEGIN; CASE WHEN index_id IN ( 1, 0 ) THEN ''TABLE'' ELSE ''NonClustered'' END AS [Object Type], - index_definition AS [Definition: [Property]] ColumnName {datatype maxbytes}], + LEFT(index_definition,4000) 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], @@ -26118,7 +26164,7 @@ BEGIN SET NOCOUNT ON; SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED; -SELECT @Version = '2.6', @VersionDate = '20190702'; +SELECT @Version = '2.7', @VersionDate = '20190826'; IF(@VersionCheckMode = 1) @@ -27386,7 +27432,7 @@ BEGIN /*First BEGIN*/ SET NOCOUNT ON; SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED; -SELECT @Version = '3.6', @VersionDate = '20190702'; +SELECT @Version = '3.7', @VersionDate = '20190826'; IF(@VersionCheckMode = 1) BEGIN RETURN; @@ -33111,7 +33157,7 @@ BEGIN SET NOCOUNT ON; SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED; - SELECT @Version = '7.6', @VersionDate = '20190702'; + SELECT @Version = '7.7', @VersionDate = '20190826'; IF(@VersionCheckMode = 1) BEGIN