diff --git a/Install-All-Scripts.sql b/Install-All-Scripts.sql
index cf1bc0e8..547300b1 100644
--- a/Install-All-Scripts.sql
+++ b/Install-All-Scripts.sql
@@ -38,7 +38,7 @@ SET STATISTICS XML OFF;
BEGIN;
-SELECT @Version = '8.17', @VersionDate = '20231010';
+SELECT @Version = '8.18', @VersionDate = '20231222';
IF(@VersionCheckMode = 1)
BEGIN
@@ -1375,7 +1375,7 @@ SET STATISTICS XML OFF;
BEGIN;
-SELECT @Version = '8.17', @VersionDate = '20231010';
+SELECT @Version = '8.18', @VersionDate = '20231222';
IF(@VersionCheckMode = 1)
BEGIN
@@ -2900,7 +2900,7 @@ AS
SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
- SELECT @Version = '8.17', @VersionDate = '20231010';
+ SELECT @Version = '8.18', @VersionDate = '20231222';
SET @OutputType = UPPER(@OutputType);
IF(@VersionCheckMode = 1)
@@ -3058,14 +3058,11 @@ AS
,@SkipXPFixedDrives bit = 0
,@SkipXPCMDShell bit = 0
,@SkipMaster bit = 0
- ,@SkipMSDB bit = 0
+ ,@SkipMSDB_objs bit = 0
+ ,@SkipMSDB_jobs bit = 0
,@SkipModel bit = 0
,@SkipTempDB bit = 0
,@SkipValidateLogins bit = 0
- /* Variables for check 211: */
- ,@powerScheme varchar(36)
- ,@cpu_speed_mhz int
- ,@cpu_speed_ghz decimal(18,2);
DECLARE
@db_perms table
@@ -3140,38 +3137,6 @@ AS
SET @SkipTrace = 1;
END; /*We need this permission to execute trace stuff, apparently*/
- IF ISNULL(@SkipXPRegRead, 0) != 1 /*If @SkipXPRegRead hasn't been set to 1 by the caller*/
- BEGIN
- BEGIN TRY
- /* Get power plan if set by group policy [Git Hub Issue #1620] */
- EXEC xp_regread @rootkey = N'HKEY_LOCAL_MACHINE',
- @key = N'SOFTWARE\Policies\Microsoft\Power\PowerSettings',
- @value_name = N'ActivePowerScheme',
- @value = @powerScheme OUTPUT,
- @no_output = N'no_output';
-
- IF @powerScheme IS NULL /* If power plan was not set by group policy, get local value [Git Hub Issue #1620]*/
- EXEC xp_regread @rootkey = N'HKEY_LOCAL_MACHINE',
- @key = N'SYSTEM\CurrentControlSet\Control\Power\User\PowerSchemes',
- @value_name = N'ActivePowerScheme',
- @value = @powerScheme OUTPUT;
-
- /* Get the cpu speed*/
- EXEC xp_regread @rootkey = N'HKEY_LOCAL_MACHINE',
- @key = N'HARDWARE\DESCRIPTION\System\CentralProcessor\0',
- @value_name = N'~MHz',
- @value = @cpu_speed_mhz OUTPUT;
-
- /* Convert the Megahertz to Gigahertz */
- SET @cpu_speed_ghz = CAST(CAST(@cpu_speed_mhz AS decimal) / 1000 AS decimal(18,2));
-
- SET @SkipXPRegRead = 0; /*We could execute xp_regread*/
- END TRY
- BEGIN CATCH
- SET @SkipXPRegRead = 1; /*We have don't have execute rights or xp_regread throws an error so skip it*/
- END CATCH;
- END; /*Need execute on xp_regread*/
-
IF NOT EXISTS
(
SELECT
@@ -3241,7 +3206,7 @@ AS
END;
END;
- IF ISNULL(@SkipMSDB, 0) != 1 /*If @SkipMSDB hasn't been set to 1 by the caller*/
+ IF ISNULL(@SkipMSDB_objs, 0) != 1 /*If @SkipMSDB_objs hasn't been set to 1 by the caller*/
BEGIN
IF EXISTS
(
@@ -3257,16 +3222,45 @@ AS
FROM msdb.sys.objects
)
BEGIN
- SET @SkipMSDB = 0; /*We have read permissions in the msdb database, and can view the objects*/
+ SET @SkipMSDB_objs = 0; /*We have read permissions in the msdb database, and can view the objects*/
+ END;
+ END TRY
+ BEGIN CATCH
+ SET @SkipMSDB_objs = 1; /*We have read permissions in the msdb database ... oh wait we got tricked, we can't view the objects*/
+ END CATCH;
+ END;
+ ELSE
+ BEGIN
+ SET @SkipMSDB_objs = 1; /*We don't have read permissions in the msdb database*/
+ END;
+ END;
+
+ IF ISNULL(@SkipMSDB_jobs, 0) != 1 /*If @SkipMSDB_jobs hasn't been set to 1 by the caller*/
+ BEGIN
+ IF EXISTS
+ (
+ SELECT 1/0
+ FROM @db_perms
+ WHERE database_name = N'msdb'
+ )
+ BEGIN
+ BEGIN TRY
+ IF EXISTS
+ (
+ SELECT 1/0
+ FROM msdb.dbo.sysjobs
+ )
+ BEGIN
+ SET @SkipMSDB_jobs = 0; /*We have read permissions in the msdb database, and can view the objects*/
END;
END TRY
BEGIN CATCH
- SET @SkipMSDB = 1; /*We have read permissions in the msdb database ... oh wait we got tricked, we can't view the objects*/
+ SET @SkipMSDB_jobs = 1; /*We have read permissions in the msdb database ... oh wait we got tricked, we can't view the objects*/
END CATCH;
END;
ELSE
BEGIN
- SET @SkipMSDB = 1; /*We don't have read permissions in the msdb database*/
+ SET @SkipMSDB_jobs = 1; /*We don't have read permissions in the msdb database*/
END;
END;
END;
@@ -3438,17 +3432,34 @@ AS
INSERT #SkipChecks (DatabaseName, CheckID, ServerName)
SELECT
v.*
- FROM (VALUES(NULL, 6, NULL), /*Jobs Owned By Users*/
- (NULL, 28, NULL), /*SQL Agent Job Runs at Startup*/
- (NULL, 57, NULL), /*Tables in the MSDB Database*/
+ FROM (VALUES(NULL, 28, NULL)) AS v (DatabaseName, CheckID, ServerName) /*Tables in the MSDB Database*/
+ WHERE @SkipMSDB_objs = 1;
+
+ INSERT #SkipChecks (DatabaseName, CheckID, ServerName)
+ SELECT
+ v.*
+ FROM (VALUES
+ /*sysjobs checks*/
+ (NULL, 6, NULL), /*Jobs Owned By Users*/
+ (NULL, 57, NULL), /*SQL Agent Job Runs at Startup*/
(NULL, 79, NULL), /*Shrink Database Job*/
(NULL, 94, NULL), /*Agent Jobs Without Failure Emails*/
(NULL, 123, NULL), /*Agent Jobs Starting Simultaneously*/
(NULL, 180, NULL), /*Shrink Database Step In Maintenance Plan*/
(NULL, 181, NULL), /*Repetitive Maintenance Tasks*/
- (NULL, 219, NULL) /*Alerts Without Event Descriptions*/
- ) AS v (DatabaseName, CheckID, ServerName)
- WHERE @SkipMSDB = 1;
+
+ /*sysalerts checks*/
+ (NULL, 30, NULL), /*Not All Alerts Configured*/
+ (NULL, 59, NULL), /*Alerts Configured without Follow Up*/
+ (NULL, 61, NULL), /*No Alerts for Sev 19-25*/
+ (NULL, 96, NULL), /*No Alerts for Corruption*/
+ (NULL, 98, NULL), /*Alerts Disabled*/
+ (NULL, 219, NULL), /*Alerts Without Event Descriptions*/
+
+ /*sysoperators*/
+ (NULL, 31, NULL) /*No Operators Configured/Enabled*/
+ ) AS v (DatabaseName, CheckID, ServerName)
+ WHERE @SkipMSDB_jobs = 1;
INSERT #SkipChecks (DatabaseName, CheckID, ServerName)
SELECT
@@ -3492,6 +3503,25 @@ AS
FROM (VALUES(NULL, 2301, NULL)) AS v (DatabaseName, CheckID, ServerName) /*sp_validatelogins*/
WHERE @SkipValidateLogins = 1
+ IF @sa = 0
+ BEGIN
+ INSERT INTO #BlitzResults
+ ( CheckID ,
+ Priority ,
+ FindingsGroup ,
+ Finding ,
+ URL ,
+ Details
+ )
+ SELECT 223 AS CheckID ,
+ 0 AS Priority ,
+ 'Informational' AS FindingsGroup ,
+ 'Some Checks Skipped' AS Finding ,
+ '' AS URL ,
+ 'User ''' + @SUSER_NAME + ''' is not part of the sysadmin role, so we skipped some checks that are not possible due to lack of permissions.' AS Details;
+ END;
+ /*End of SkipsChecks added due to permissions*/
+
IF @SkipChecksTable IS NOT NULL
AND @SkipChecksSchema IS NOT NULL
AND @SkipChecksDatabase IS NOT NULL
@@ -11536,122 +11566,147 @@ IF @ProductVersionMajor >= 10 AND NOT EXISTS ( SELECT 1
EXECUTE(@StringToExecute);
END;
- /*
- Starting with SQL Server 2014 SP2, Instant File Initialization
- is logged in the SQL Server Error Log.
- */
- IF NOT EXISTS ( SELECT 1
- FROM #SkipChecks
- WHERE DatabaseName IS NULL AND CheckID = 193 )
- AND ((@ProductVersionMajor >= 13) OR (@ProductVersionMajor = 12 AND @ProductVersionMinor >= 5000))
+ /* Performance - Instant File Initialization Not Enabled - Check 192 */
+ /* Server Info - Instant File Initialization Enabled - Check 193 */
+ IF NOT EXISTS ( SELECT 1/0
+ FROM #SkipChecks
+ WHERE DatabaseName IS NULL AND CheckID = 192 /* IFI disabled check disabled */
+ ) OR NOT EXISTS
+ ( SELECT 1/0
+ FROM #SkipChecks
+ WHERE DatabaseName IS NULL AND CheckID = 193 /* IFI enabled check disabled */
+ )
+ BEGIN
+ IF @Debug IN (1, 2) RAISERROR('Running CheckId [%d] and CheckId [%d].', 0, 1, 192, 193) WITH NOWAIT;
+
+ DECLARE @IFISetting varchar(1) = N'N'
+ ,@IFIReadDMVFailed bit = 0
+ ,@IFIAllFailed bit = 0;
+
+ /* See if we can get the instant_file_initialization_enabled column from sys.dm_server_services */
+ IF EXISTS
+ (
+ SELECT 1/0
+ FROM sys.all_columns
+ WHERE [object_id] = OBJECT_ID(N'[sys].[dm_server_services]')
+ AND [name] = N'instant_file_initialization_enabled'
+ )
BEGIN
+ /* This needs to be a "dynamic" SQL statement because if the 'instant_file_initialization_enabled' column doesn't exist the procedure might fail on a bind error */
+ SET @StringToExecute = N'SELECT @IFISetting = instant_file_initialization_enabled' + @crlf +
+ N'FROM sys.dm_server_services' + @crlf +
+ N'WHERE filename LIKE ''%sqlservr.exe%''' + @crlf +
+ N'OPTION (RECOMPILE);';
+
+ IF @Debug = 2 AND @StringToExecute IS NOT NULL PRINT @StringToExecute;
+ IF @Debug = 2 AND @StringToExecute IS NULL PRINT '@StringToExecute has gone NULL, for some reason.';
+
+ EXEC dbo.sp_executesql
+ @StringToExecute
+ ,N'@IFISetting varchar(1) OUTPUT'
+ ,@IFISetting = @IFISetting OUTPUT
- IF @Debug IN (1, 2) RAISERROR('Running CheckId [%d].', 0, 1, 193) WITH NOWAIT;
-
- -- If this is Amazon RDS, use rdsadmin.dbo.rds_read_error_log
- IF LEFT(CAST(SERVERPROPERTY('ComputerNamePhysicalNetBIOS') AS VARCHAR(8000)), 8) = 'EC2AMAZ-'
- AND LEFT(CAST(SERVERPROPERTY('MachineName') AS VARCHAR(8000)), 8) = 'EC2AMAZ-'
- AND db_id('rdsadmin') IS NOT NULL
- AND EXISTS(SELECT * FROM master.sys.all_objects WHERE name IN ('rds_startup_tasks', 'rds_help_revlogin', 'rds_hexadecimal', 'rds_failover_tracking', 'rds_database_tracking', 'rds_track_change'))
- BEGIN
- INSERT INTO #ErrorLog
- EXEC rdsadmin.dbo.rds_read_error_log 0, 1, N'Database Instant File Initialization: enabled';
- END
- ELSE
- BEGIN
- BEGIN TRY
- INSERT INTO #ErrorLog
- EXEC sys.xp_readerrorlog 0, 1, N'Database Instant File Initialization: enabled';
- END TRY
- BEGIN CATCH
- IF @Debug IN (1, 2) RAISERROR('No permissions to execute xp_readerrorlog.', 0, 1) WITH NOWAIT;
- END CATCH
- END
-
- IF EXISTS
- (
- SELECT 1/0
- FROM #ErrorLog
- WHERE LEFT([Text], 45) = N'Database Instant File Initialization: enabled'
- )
- BEGIN
- INSERT INTO #BlitzResults
- ( CheckID ,
- [Priority] ,
- FindingsGroup ,
- Finding ,
- URL ,
- Details
- )
- SELECT
- 193 AS [CheckID] ,
- 250 AS [Priority] ,
- 'Server Info' AS [FindingsGroup] ,
- 'Instant File Initialization Enabled' AS [Finding] ,
- 'https://www.brentozar.com/go/instant' AS [URL] ,
- 'The service account has the Perform Volume Maintenance Tasks permission.';
- END;
- else -- if version of sql server has instant_file_initialization_enabled column in dm_server_services, check that too
- -- in the event the error log has been cycled and the startup messages are not in the current error log
- begin
- 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_server_services'
- AND c.name = 'instant_file_initialization_enabled' )
- begin
- SET @StringToExecute = N'
- INSERT INTO #BlitzResults
- ( CheckID ,
- [Priority] ,
- FindingsGroup ,
- Finding ,
- URL ,
- Details
- )
- SELECT
- 193 AS [CheckID] ,
- 250 AS [Priority] ,
- ''Server Info'' AS [FindingsGroup] ,
- ''Instant File Initialization Enabled'' AS [Finding] ,
- ''https://www.brentozar.com/go/instant'' AS [URL] ,
- ''The service account has the Perform Volume Maintenance Tasks permission.''
- where exists (select 1 FROM sys.dm_server_services
- WHERE instant_file_initialization_enabled = ''Y''
- AND filename LIKE ''%sqlservr.exe%'')
- OPTION (RECOMPILE);';
- EXEC(@StringToExecute);
- end;
- end;
- END;
+ SET @IFIReadDMVFailed = 0;
+ END
+ ELSE
+ /* We couldn't get the instant_file_initialization_enabled column from sys.dm_server_services, fall back to read error log */
+ BEGIN
+ SET @IFIReadDMVFailed = 1;
+ /* If this is Amazon RDS, we'll use the rdsadmin.dbo.rds_read_error_log */
+ IF LEFT(CAST(SERVERPROPERTY('ComputerNamePhysicalNetBIOS') AS VARCHAR(8000)), 8) = 'EC2AMAZ-'
+ AND LEFT(CAST(SERVERPROPERTY('MachineName') AS VARCHAR(8000)), 8) = 'EC2AMAZ-'
+ AND db_id('rdsadmin') IS NOT NULL
+ AND EXISTS ( SELECT 1/0
+ FROM master.sys.all_objects
+ WHERE name IN ('rds_startup_tasks', 'rds_help_revlogin', 'rds_hexadecimal', 'rds_failover_tracking', 'rds_database_tracking', 'rds_track_change')
+ )
+ BEGIN
+ /* Amazon RDS detected, read rdsadmin.dbo.rds_read_error_log */
+ INSERT INTO #ErrorLog
+ EXEC rdsadmin.dbo.rds_read_error_log 0, 1, N'Database Instant File Initialization: enabled';
+ END
+ ELSE
+ BEGIN
+ /* Try to read the error log, this might fail due to permissions */
+ BEGIN TRY
+ INSERT INTO #ErrorLog
+ EXEC sys.xp_readerrorlog 0, 1, N'Database Instant File Initialization: enabled';
+ END TRY
+ BEGIN CATCH
+ IF @Debug IN (1, 2) RAISERROR('No permissions to execute xp_readerrorlog.', 0, 1) WITH NOWAIT;
+ SET @IFIAllFailed = 1;
+ END CATCH
+ END;
+ END;
+
+ IF @IFIAllFailed = 0
+ BEGIN
+ IF @IFIReadDMVFailed = 1
+ /* We couldn't read the DMV so set the @IFISetting variable using the error log */
+ BEGIN
+ IF EXISTS ( SELECT 1/0
+ FROM #ErrorLog
+ WHERE LEFT([Text], 45) = N'Database Instant File Initialization: enabled'
+ )
+ BEGIN
+ SET @IFISetting = 'Y';
+ END
+ ELSE
+ BEGIN
+ SET @IFISetting = 'N';
+ END;
+ END;
+
+ IF NOT EXISTS ( SELECT 1/0
+ FROM #SkipChecks
+ WHERE DatabaseName IS NULL AND CheckID = 192 /* IFI disabled check disabled */
+ ) AND @IFISetting = 'N'
+ BEGIN
+ INSERT INTO #BlitzResults
+ (
+ CheckID ,
+ [Priority] ,
+ FindingsGroup ,
+ Finding ,
+ URL ,
+ Details
+ )
+ SELECT
+ 192 AS [CheckID] ,
+ 50 AS [Priority] ,
+ 'Performance' AS [FindingsGroup] ,
+ 'Instant File Initialization Not Enabled' AS [Finding] ,
+ 'https://www.brentozar.com/go/instant' AS [URL] ,
+ 'Consider enabling IFI for faster restores and data file growths.' AS [Details]
+ END;
+
+ IF NOT EXISTS ( SELECT 1/0
+ FROM #SkipChecks
+ WHERE DatabaseName IS NULL AND CheckID = 193 /* IFI enabled check disabled */
+ ) AND @IFISetting = 'Y'
+ BEGIN
+ INSERT INTO #BlitzResults
+ (
+ CheckID ,
+ [Priority] ,
+ FindingsGroup ,
+ Finding ,
+ URL ,
+ Details
+ )
+ SELECT
+ 193 AS [CheckID] ,
+ 250 AS [Priority] ,
+ 'Server Info' AS [FindingsGroup] ,
+ 'Instant File Initialization Enabled' AS [Finding] ,
+ 'https://www.brentozar.com/go/instant' AS [URL] ,
+ 'The service account has the Perform Volume Maintenance Tasks permission.' AS [Details]
+ END;
+ END;
+ END;
- /* Server Info - Instant File Initialization Not Enabled - Check 192 - SQL Server 2016 SP1 and newer */
- IF NOT EXISTS ( SELECT 1
- FROM #SkipChecks
- WHERE DatabaseName IS NULL AND CheckID = 192 )
- AND EXISTS ( SELECT *
- FROM sys.all_objects o
- INNER JOIN sys.all_columns c ON o.object_id = c.object_id
- WHERE o.name = 'dm_server_services'
- AND c.name = 'instant_file_initialization_enabled' )
- BEGIN
-
- IF @Debug IN (1, 2) RAISERROR('Running CheckId [%d].', 0, 1, 192) WITH NOWAIT;
-
- SET @StringToExecute = 'INSERT INTO #BlitzResults (CheckID, Priority, FindingsGroup, Finding, URL, Details)
- SELECT 192 AS CheckID ,
- 50 AS Priority ,
- ''Server Info'' AS FindingsGroup ,
- ''Instant File Initialization Not Enabled'' AS Finding ,
- ''https://www.brentozar.com/go/instant'' AS URL ,
- ''Consider enabling IFI for faster restores and data file growths.''
- FROM sys.dm_server_services WHERE instant_file_initialization_enabled <> ''Y'' AND filename LIKE ''%sqlservr.exe%'' OPTION (RECOMPILE);';
-
- IF @Debug = 2 AND @StringToExecute IS NOT NULL PRINT @StringToExecute;
- IF @Debug = 2 AND @StringToExecute IS NULL PRINT '@StringToExecute has gone NULL, for some reason.';
-
- EXECUTE(@StringToExecute);
- END;
+ /* End of checkId 192 */
+ /* End of checkId 193 */
IF NOT EXISTS ( SELECT 1
FROM #SkipChecks
@@ -12029,7 +12084,39 @@ IF @ProductVersionMajor >= 10 AND NOT EXISTS ( SELECT 1
WHERE DatabaseName IS NULL AND CheckID = 211 )
BEGIN
+ /* Variables for check 211: */
+ DECLARE
+ @powerScheme varchar(36)
+ ,@cpu_speed_mhz int
+ ,@cpu_speed_ghz decimal(18,2)
+ ,@ExecResult int;
+
IF @Debug IN (1, 2) RAISERROR('Running CheckId [%d].', 0, 1, 211) WITH NOWAIT;
+ IF @sa = 0 RAISERROR('The errors: ''xp_regread() returned error 5, ''Access is denied.'''' can be safely ignored', 0, 1) WITH NOWAIT;
+
+ /* Get power plan if set by group policy [Git Hub Issue #1620] */
+ EXEC xp_regread @rootkey = N'HKEY_LOCAL_MACHINE',
+ @key = N'SOFTWARE\Policies\Microsoft\Power\PowerSettings',
+ @value_name = N'ActivePowerScheme',
+ @value = @powerScheme OUTPUT,
+ @no_output = N'no_output';
+
+ IF @powerScheme IS NULL /* If power plan was not set by group policy, get local value [Git Hub Issue #1620]*/
+ EXEC xp_regread @rootkey = N'HKEY_LOCAL_MACHINE',
+ @key = N'SYSTEM\CurrentControlSet\Control\Power\User\PowerSchemes',
+ @value_name = N'ActivePowerScheme',
+ @value = @powerScheme OUTPUT;
+
+ /* Get the cpu speed*/
+ EXEC @ExecResult = xp_regread @rootkey = N'HKEY_LOCAL_MACHINE',
+ @key = N'HARDWARE\DESCRIPTION\System\CentralProcessor\0',
+ @value_name = N'~MHz',
+ @value = @cpu_speed_mhz OUTPUT;
+
+ /* Convert the Megahertz to Gigahertz */
+ IF @ExecResult != 0 RAISERROR('We couldn''t retrieve the CPU speed, you will see Unknown in the results', 0, 1)
+
+ SET @cpu_speed_ghz = CAST(CAST(@cpu_speed_mhz AS decimal) / 1000 AS decimal(18,2));
INSERT INTO #BlitzResults
( CheckID ,
@@ -12045,7 +12132,7 @@ IF @ProductVersionMajor >= 10 AND NOT EXISTS ( SELECT 1
'Power Plan' AS Finding,
'https://www.brentozar.com/blitz/power-mode/' AS URL,
'Your server has '
- + CAST(@cpu_speed_ghz as VARCHAR(4))
+ + ISNULL(CAST(@cpu_speed_ghz as VARCHAR(8)), 'Unknown ')
+ 'GHz CPUs, and is in '
+ CASE @powerScheme
WHEN 'a1841308-3541-4fab-bc81-f71556f20b4a'
@@ -12701,20 +12788,22 @@ IF @ProductVersionMajor >= 10 AND NOT EXISTS ( SELECT 1
FROM #BlitzResults
WHERE Priority > 0 AND Priority < 255 AND FindingsGroup IS NOT NULL AND Finding IS NOT NULL
AND FindingsGroup <> 'Security' /* Specifically excluding security checks for public exports */)
- SELECT
- CASE
- WHEN r.Priority <> COALESCE(rPrior.Priority, 0) OR r.FindingsGroup <> rPrior.FindingsGroup THEN @crlf + N'**Priority ' + CAST(COALESCE(r.Priority,N'') AS NVARCHAR(5)) + N': ' + COALESCE(r.FindingsGroup,N'') + N'**:' + @crlf + @crlf
- ELSE N''
- END
- + CASE WHEN r.Finding <> COALESCE(rPrior.Finding,N'') AND r.Finding <> COALESCE(rNext.Finding,N'') THEN N'- ' + COALESCE(r.Finding,N'') + N' ' + COALESCE(r.DatabaseName, N'') + N' - ' + COALESCE(r.Details,N'') + @crlf
- WHEN r.Finding <> COALESCE(rPrior.Finding,N'') AND r.Finding = rNext.Finding AND r.Details = rNext.Details THEN N'- ' + COALESCE(r.Finding,N'') + N' - ' + COALESCE(r.Details,N'') + @crlf + @crlf + N' * ' + COALESCE(r.DatabaseName, N'') + @crlf
- WHEN r.Finding <> COALESCE(rPrior.Finding,N'') AND r.Finding = rNext.Finding THEN N'- ' + COALESCE(r.Finding,N'') + @crlf + CASE WHEN r.DatabaseName IS NULL THEN N'' ELSE N' * ' + COALESCE(r.DatabaseName,N'') END + CASE WHEN r.Details <> rPrior.Details THEN N' - ' + COALESCE(r.Details,N'') + @crlf ELSE '' END
- ELSE CASE WHEN r.DatabaseName IS NULL THEN N'' ELSE N' * ' + COALESCE(r.DatabaseName,N'') END + CASE WHEN r.Details <> rPrior.Details THEN N' - ' + COALESCE(r.Details,N'') + @crlf ELSE N'' + @crlf END
- END + @crlf
- FROM Results r
- LEFT OUTER JOIN Results rPrior ON r.rownum = rPrior.rownum + 1
- LEFT OUTER JOIN Results rNext ON r.rownum = rNext.rownum - 1
- ORDER BY r.rownum FOR XML PATH(N'');
+ SELECT
+ Markdown = CONVERT(XML, STUFF((SELECT
+ CASE
+ WHEN r.Priority <> COALESCE(rPrior.Priority, 0) OR r.FindingsGroup <> rPrior.FindingsGroup THEN @crlf + N'**Priority ' + CAST(COALESCE(r.Priority,N'') AS NVARCHAR(5)) + N': ' + COALESCE(r.FindingsGroup,N'') + N'**:' + @crlf + @crlf
+ ELSE N''
+ END
+ + CASE WHEN r.Finding <> COALESCE(rPrior.Finding,N'') AND r.Finding <> COALESCE(rNext.Finding,N'') THEN N'- ' + COALESCE(r.Finding,N'') + N' ' + COALESCE(r.DatabaseName, N'') + N' - ' + COALESCE(r.Details,N'') + @crlf
+ WHEN r.Finding <> COALESCE(rPrior.Finding,N'') AND r.Finding = rNext.Finding AND r.Details = rNext.Details THEN N'- ' + COALESCE(r.Finding,N'') + N' - ' + COALESCE(r.Details,N'') + @crlf + @crlf + N' * ' + COALESCE(r.DatabaseName, N'') + @crlf
+ WHEN r.Finding <> COALESCE(rPrior.Finding,N'') AND r.Finding = rNext.Finding THEN N'- ' + COALESCE(r.Finding,N'') + @crlf + @crlf + CASE WHEN r.DatabaseName IS NULL THEN N'' ELSE N' * ' + COALESCE(r.DatabaseName,N'') END + CASE WHEN r.Details <> rPrior.Details THEN N' - ' + COALESCE(r.Details,N'') + @crlf ELSE '' END
+ ELSE CASE WHEN r.DatabaseName IS NULL THEN N'' ELSE N' * ' + COALESCE(r.DatabaseName,N'') END + CASE WHEN r.Details <> rPrior.Details THEN N' - ' + COALESCE(r.Details,N'') + @crlf ELSE N'' + @crlf END
+ END + @crlf
+ FROM Results r
+ LEFT OUTER JOIN Results rPrior ON r.rownum = rPrior.rownum + 1
+ LEFT OUTER JOIN Results rNext ON r.rownum = rNext.rownum - 1
+ ORDER BY r.rownum FOR XML PATH(N''), ROOT('Markdown'), TYPE).value('/Markdown[1]','VARCHAR(MAX)'), 1, 2, '')
+ + '');
END;
ELSE IF @OutputType = 'XML'
BEGIN
@@ -12878,7 +12967,7 @@ AS
SET NOCOUNT ON;
SET STATISTICS XML OFF;
-SELECT @Version = '8.17', @VersionDate = '20231010';
+SELECT @Version = '8.18', @VersionDate = '20231222';
IF(@VersionCheckMode = 1)
BEGIN
@@ -13756,7 +13845,7 @@ AS
SET STATISTICS XML OFF;
SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
- SELECT @Version = '8.17', @VersionDate = '20231010';
+ SELECT @Version = '8.18', @VersionDate = '20231222';
IF(@VersionCheckMode = 1)
BEGIN
@@ -15538,7 +15627,7 @@ SET NOCOUNT ON;
SET STATISTICS XML OFF;
SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
-SELECT @Version = '8.17', @VersionDate = '20231010';
+SELECT @Version = '8.18', @VersionDate = '20231222';
SET @OutputType = UPPER(@OutputType);
IF(@VersionCheckMode = 1)
@@ -22595,16 +22684,16 @@ END ';
IF @Debug = 1
BEGIN
- PRINT SUBSTRING(@StringToExecute, 0, 4000);
- PRINT SUBSTRING(@StringToExecute, 4000, 8000);
- PRINT SUBSTRING(@StringToExecute, 8000, 12000);
- PRINT SUBSTRING(@StringToExecute, 12000, 16000);
- PRINT SUBSTRING(@StringToExecute, 16000, 20000);
- PRINT SUBSTRING(@StringToExecute, 20000, 24000);
- PRINT SUBSTRING(@StringToExecute, 24000, 28000);
- PRINT SUBSTRING(@StringToExecute, 28000, 32000);
- PRINT SUBSTRING(@StringToExecute, 32000, 36000);
- PRINT SUBSTRING(@StringToExecute, 36000, 40000);
+ PRINT SUBSTRING(@StringToExecute, 1, 4000);
+ PRINT SUBSTRING(@StringToExecute, 4001, 4000);
+ PRINT SUBSTRING(@StringToExecute, 8001, 4000);
+ PRINT SUBSTRING(@StringToExecute, 12001, 4000);
+ PRINT SUBSTRING(@StringToExecute, 16001, 4000);
+ PRINT SUBSTRING(@StringToExecute, 20001, 4000);
+ PRINT SUBSTRING(@StringToExecute, 24001, 4000);
+ PRINT SUBSTRING(@StringToExecute, 28001, 4000);
+ PRINT SUBSTRING(@StringToExecute, 32001, 4000);
+ PRINT SUBSTRING(@StringToExecute, 36001, 4000);
END;
EXEC sp_executesql @StringToExecute, N'@Top INT, @min_duration INT, @min_back INT, @CheckDateOverride DATETIMEOFFSET, @MinimumExecutionCount INT', @Top, @DurationFilter_i, @MinutesBack, @CheckDateOverride, @MinimumExecutionCount;
@@ -22897,7 +22986,7 @@ SET NOCOUNT ON;
SET STATISTICS XML OFF;
SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
-SELECT @Version = '8.17', @VersionDate = '20231010';
+SELECT @Version = '8.18', @VersionDate = '20231222';
SET @OutputType = UPPER(@OutputType);
IF(@VersionCheckMode = 1)
@@ -24063,16 +24152,16 @@ BEGIN TRY
RAISERROR (N'Inserting data into #IndexColumns for clustered indexes and heaps',0,1) WITH NOWAIT;
IF @Debug = 1
BEGIN
- PRINT SUBSTRING(@dsql, 0, 4000);
- PRINT SUBSTRING(@dsql, 4000, 8000);
- PRINT SUBSTRING(@dsql, 8000, 12000);
- PRINT SUBSTRING(@dsql, 12000, 16000);
- PRINT SUBSTRING(@dsql, 16000, 20000);
- PRINT SUBSTRING(@dsql, 20000, 24000);
- PRINT SUBSTRING(@dsql, 24000, 28000);
- PRINT SUBSTRING(@dsql, 28000, 32000);
- PRINT SUBSTRING(@dsql, 32000, 36000);
- PRINT SUBSTRING(@dsql, 36000, 40000);
+ PRINT SUBSTRING(@dsql, 1, 4000);
+ PRINT SUBSTRING(@dsql, 4001, 4000);
+ PRINT SUBSTRING(@dsql, 8001, 4000);
+ PRINT SUBSTRING(@dsql, 12001, 4000);
+ PRINT SUBSTRING(@dsql, 16001, 4000);
+ PRINT SUBSTRING(@dsql, 20001, 4000);
+ PRINT SUBSTRING(@dsql, 24001, 4000);
+ PRINT SUBSTRING(@dsql, 28001, 4000);
+ PRINT SUBSTRING(@dsql, 32001, 4000);
+ PRINT SUBSTRING(@dsql, 36001, 4000);
END;
BEGIN TRY
INSERT #IndexColumns ( database_id, [schema_name], [object_id], index_id, key_ordinal, is_included_column, is_descending_key, partition_ordinal,
@@ -25440,6 +25529,7 @@ SELECT
FROM #IndexSanity;
RAISERROR (N'Populate #PartitionCompressionInfo.',0,1) WITH NOWAIT;
+IF OBJECT_ID('tempdb..#maps') IS NOT NULL DROP TABLE #maps;
WITH maps
AS
(
@@ -25454,6 +25544,7 @@ SELECT *
INTO #maps
FROM maps;
+IF OBJECT_ID('tempdb..#grps') IS NOT NULL DROP TABLE #grps;
WITH grps
AS
(
@@ -29079,10 +29170,11 @@ WITH RECOMPILE
AS
BEGIN
SET STATISTICS XML OFF;
- SET NOCOUNT, XACT_ABORT ON;
+ SET NOCOUNT ON;
+ SET XACT_ABORT OFF;
SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
- SELECT @Version = '8.17', @VersionDate = '20231010';
+ SELECT @Version = '8.18', @VersionDate = '20231222';
IF @VersionCheckMode = 1
BEGIN
@@ -29206,6 +29298,20 @@ BEGIN
THEN 1
ELSE 0
END,
+ @MI bit =
+ CASE
+ WHEN
+ (
+ SELECT
+ CONVERT
+ (
+ integer,
+ SERVERPROPERTY('EngineEdition')
+ )
+ ) = 8
+ THEN 1
+ ELSE 0
+ END,
@RDS bit =
CASE
WHEN LEFT(CAST(SERVERPROPERTY('ComputerNamePhysicalNetBIOS') AS varchar(8000)), 8) <> 'EC2AMAZ-'
@@ -29344,6 +29450,17 @@ BEGIN
@StartDateUTC = @StartDate,
@EndDateUTC = @EndDate;
+ IF
+ (
+ @MI = 1
+ AND @EventSessionName = N'system_health'
+ AND @TargetSessionType IS NULL
+ )
+ BEGIN
+ SET
+ @TargetSessionType = N'ring_buffer';
+ END;
+
IF @Azure = 0
BEGIN
IF NOT EXISTS
@@ -29361,7 +29478,7 @@ BEGIN
RETURN;
END;
END;
-
+
IF @Azure = 1
BEGIN
IF NOT EXISTS
@@ -30891,7 +31008,7 @@ BEGIN
COUNT_BIG(DISTINCT dp.event_date)
) +
N' deadlocks.',
- sort_order =
+ sort_order =
ROW_NUMBER()
OVER (ORDER BY COUNT_BIG(DISTINCT dp.event_date) DESC)
FROM #deadlock_process AS dp
@@ -30931,7 +31048,7 @@ BEGIN
SELECT
1/0
FROM sys.databases AS d
- WHERE d.name = dow.database_name
+ WHERE d.name COLLATE DATABASE_DEFAULT = dow.database_name COLLATE DATABASE_DEFAULT
AND d.is_read_committed_snapshot_on = 1
)
THEN N'You already enabled RCSI, but...'
@@ -30946,7 +31063,7 @@ BEGIN
COUNT_BIG(DISTINCT dow.event_date)
) +
N' deadlock(s) between read queries and modification queries.',
- sort_order =
+ sort_order =
ROW_NUMBER()
OVER (ORDER BY COUNT_BIG(DISTINCT dow.event_date) DESC)
FROM #deadlock_owner_waiter AS dow
@@ -31008,7 +31125,7 @@ BEGIN
COUNT_BIG(DISTINCT dow.event_date)
) +
N' deadlock(s).',
- sort_order =
+ sort_order =
ROW_NUMBER()
OVER (ORDER BY COUNT_BIG(DISTINCT dow.event_date) DESC)
FROM #deadlock_owner_waiter AS dow
@@ -31051,7 +31168,7 @@ BEGIN
COUNT_BIG(DISTINCT dow.event_date)
) +
N' deadlock(s).',
- sort_order =
+ sort_order =
ROW_NUMBER()
OVER (ORDER BY COUNT_BIG(DISTINCT dow.event_date) DESC)
FROM #deadlock_owner_waiter AS dow
@@ -31100,7 +31217,7 @@ BEGIN
COUNT_BIG(DISTINCT dow.event_date)
) +
N' deadlock(s).',
- sort_order =
+ sort_order =
ROW_NUMBER()
OVER (ORDER BY COUNT_BIG(DISTINCT dow.event_date) DESC)
FROM #deadlock_owner_waiter AS dow
@@ -31149,7 +31266,7 @@ BEGIN
COUNT_BIG(DISTINCT dp.event_date)
) +
N' instances of Serializable deadlocks.',
- sort_order =
+ sort_order =
ROW_NUMBER()
OVER (ORDER BY COUNT_BIG(DISTINCT dp.event_date) DESC)
FROM #deadlock_process AS dp
@@ -31192,7 +31309,7 @@ BEGIN
COUNT_BIG(DISTINCT dp.event_date)
) +
N' instances of Repeatable Read deadlocks.',
- sort_order =
+ sort_order =
ROW_NUMBER()
OVER (ORDER BY COUNT_BIG(DISTINCT dp.event_date) DESC)
FROM #deadlock_process AS dp
@@ -31254,7 +31371,7 @@ BEGIN
N'UNKNOWN'
) +
N'.',
- sort_order =
+ sort_order =
ROW_NUMBER()
OVER (ORDER BY COUNT_BIG(DISTINCT dp.event_date) DESC)
FROM #deadlock_process AS dp
@@ -31366,7 +31483,7 @@ BEGIN
1,
N''
) + N' locks.',
- sort_order =
+ sort_order =
ROW_NUMBER()
OVER (ORDER BY CONVERT(bigint, lt.lock_count) DESC)
FROM lock_types AS lt
@@ -31545,7 +31662,7 @@ BEGIN
COUNT_BIG(DISTINCT ds.id)
) +
N' deadlocks.',
- sort_order =
+ sort_order =
ROW_NUMBER()
OVER (ORDER BY COUNT_BIG(DISTINCT ds.id) DESC)
FROM #deadlock_stack AS ds
@@ -31646,19 +31763,19 @@ BEGIN
)
),
wait_time_hms =
- /*the more wait time you rack up the less accurate this gets,
+ /*the more wait time you rack up the less accurate this gets,
it's either that or erroring out*/
- CASE
- WHEN
+ CASE
+ WHEN
SUM
(
CONVERT
(
- bigint,
+ bigint,
dp.wait_time
)
)/1000 > 2147483647
- THEN
+ THEN
CONVERT
(
nvarchar(30),
@@ -31671,7 +31788,7 @@ BEGIN
(
CONVERT
(
- bigint,
+ bigint,
dp.wait_time
)
)
@@ -31682,16 +31799,16 @@ BEGIN
),
14
)
- WHEN
+ WHEN
SUM
(
CONVERT
(
- bigint,
+ bigint,
dp.wait_time
)
) BETWEEN 2147483648 AND 2147483647000
- THEN
+ THEN
CONVERT
(
nvarchar(30),
@@ -31704,7 +31821,7 @@ BEGIN
(
CONVERT
(
- bigint,
+ bigint,
dp.wait_time
)
)
@@ -31786,7 +31903,7 @@ BEGIN
14
) +
N' [dd hh:mm:ss:ms] of deadlock wait time.',
- sort_order =
+ sort_order =
ROW_NUMBER()
OVER (ORDER BY cs.total_waits DESC)
FROM chopsuey AS cs
@@ -31860,19 +31977,19 @@ BEGIN
)
) +
N' ' +
- /*the more wait time you rack up the less accurate this gets,
+ /*the more wait time you rack up the less accurate this gets,
it's either that or erroring out*/
- CASE
- WHEN
+ CASE
+ WHEN
SUM
(
CONVERT
(
- bigint,
+ bigint,
wt.total_wait_time_ms
)
)/1000 > 2147483647
- THEN
+ THEN
CONVERT
(
nvarchar(30),
@@ -31885,7 +32002,7 @@ BEGIN
(
CONVERT
(
- bigint,
+ bigint,
wt.total_wait_time_ms
)
)
@@ -31896,16 +32013,16 @@ BEGIN
),
14
)
- WHEN
+ WHEN
SUM
(
CONVERT
(
- bigint,
+ bigint,
wt.total_wait_time_ms
)
) BETWEEN 2147483648 AND 2147483647000
- THEN
+ THEN
CONVERT
(
nvarchar(30),
@@ -31918,7 +32035,7 @@ BEGIN
(
CONVERT
(
- bigint,
+ bigint,
wt.total_wait_time_ms
)
)
@@ -31951,7 +32068,7 @@ BEGIN
14
) END +
N' [dd hh:mm:ss:ms] of deadlock wait time.',
- sort_order =
+ sort_order =
ROW_NUMBER()
OVER (ORDER BY SUM(CONVERT(bigint, wt.total_wait_time_ms)) DESC)
FROM wait_time AS wt
@@ -31989,7 +32106,7 @@ BEGIN
N'There have been ' +
RTRIM(COUNT_BIG(DISTINCT aj.event_date)) +
N' deadlocks from this Agent Job and Step.',
- sort_order =
+ sort_order =
ROW_NUMBER()
OVER (ORDER BY COUNT_BIG(DISTINCT aj.event_date) DESC)
FROM #agent_job AS aj
@@ -32769,23 +32886,23 @@ BEGIN
BEGIN
SET @d = CONVERT(varchar(40), GETDATE(), 109);
RAISERROR('Results to client %s', 0, 1, @d) WITH NOWAIT;
-
+
IF @Debug = 1 BEGIN SET STATISTICS XML ON; END;
-
+
EXEC sys.sp_executesql
@deadlock_result;
-
+
IF @Debug = 1
BEGIN
SET STATISTICS XML OFF;
PRINT @deadlock_result;
END;
-
+
RAISERROR('Finished at %s', 0, 1, @d) WITH NOWAIT;
SET @d = CONVERT(varchar(40), GETDATE(), 109);
RAISERROR('Getting available execution plans for deadlocks %s', 0, 1, @d) WITH NOWAIT;
-
+
SELECT DISTINCT
available_plans =
'available_plans',
@@ -32821,7 +32938,7 @@ BEGIN
CONVERT(decimal(38, 6), deqs.total_worker_time / 1000. / deqs.execution_count),
total_elapsed_time_ms =
deqs.total_elapsed_time / 1000.,
- avg_elapsed_time =
+ avg_elapsed_time_ms =
CONVERT(decimal(38, 6), deqs.total_elapsed_time / 1000. / deqs.execution_count),
executions_per_second =
ISNULL
@@ -32833,7 +32950,7 @@ BEGIN
(
SECOND,
deqs.creation_time,
- deqs.last_execution_time
+ NULLIF(deqs.last_execution_time, '1900-01-01 00:00:00.000')
),
0
),
@@ -32852,7 +32969,7 @@ BEGIN
min_used_grant_mb =
deqs.min_used_grant_kb * 8. / 1024.,
max_used_grant_mb =
- deqs.max_used_grant_kb * 8. / 1024.,
+ deqs.max_used_grant_kb * 8. / 1024.,
deqs.min_reserved_threads,
deqs.max_reserved_threads,
deqs.min_used_threads,
@@ -32862,21 +32979,21 @@ BEGIN
FROM sys.dm_exec_query_stats AS deqs
WHERE EXISTS
(
- SELECT
- 1/0
- FROM #available_plans AS ap
- WHERE ap.sql_handle = deqs.sql_handle
+ SELECT
+ 1/0
+ FROM #available_plans AS ap
+ WHERE ap.sql_handle = deqs.sql_handle
)
AND deqs.query_hash IS NOT NULL;
-
- CREATE CLUSTERED INDEX
- deqs
+
+ CREATE CLUSTERED INDEX
+ deqs
ON #dm_exec_query_stats
(
- sql_handle,
+ sql_handle,
plan_handle
);
-
+
SELECT
ap.available_plans,
ap.database_name,
@@ -32890,7 +33007,7 @@ BEGIN
ap.total_worker_time_ms,
ap.avg_worker_time_ms,
ap.total_elapsed_time_ms,
- ap.avg_elapsed_time,
+ ap.avg_elapsed_time_ms,
ap.total_logical_reads_mb,
ap.total_physical_reads_mb,
ap.total_logical_writes_mb,
@@ -32908,7 +33025,7 @@ BEGIN
ap.statement_end_offset
FROM
(
-
+
SELECT
ap.*,
c.statement_start_offset,
@@ -32919,7 +33036,7 @@ BEGIN
c.total_worker_time_ms,
c.avg_worker_time_ms,
c.total_elapsed_time_ms,
- c.avg_elapsed_time,
+ c.avg_elapsed_time_ms,
c.executions_per_second,
c.total_physical_reads_mb,
c.total_logical_writes_mb,
@@ -32958,10 +33075,10 @@ BEGIN
OPTION(RECOMPILE, LOOP JOIN, HASH JOIN);
RAISERROR('Finished at %s', 0, 1, @d) WITH NOWAIT;
-
+
SET @d = CONVERT(varchar(40), GETDATE(), 109);
RAISERROR('Returning findings %s', 0, 1, @d) WITH NOWAIT;
-
+
SELECT
df.check_id,
df.database_name,
@@ -32973,7 +33090,7 @@ BEGIN
df.check_id,
df.sort_order
OPTION(RECOMPILE);
-
+
SET @d = CONVERT(varchar(40), GETDATE(), 109);
RAISERROR('Finished at %s', 0, 1, @d) WITH NOWAIT;
END; /*done with output to client app.*/
@@ -33212,7 +33329,7 @@ SET NOCOUNT ON;
SET STATISTICS XML OFF;
SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
-SELECT @Version = '8.17', @VersionDate = '20231010';
+SELECT @Version = '8.18', @VersionDate = '20231222';
IF(@VersionCheckMode = 1)
BEGIN
RETURN;
@@ -33273,8 +33390,6 @@ IF (SELECT CONVERT(NVARCHAR(128), SERVERPROPERTY ('EDITION'))) <> 'SQL Azure'
IF @Help = 1
BEGIN
-
- SELECT N'You have requested assistance. It will arrive as soon as humanly possible.' AS [Take four red capsules, help is on the way];
PRINT N'
sp_BlitzQueryStore from http://FirstResponderKit.org
@@ -33318,6 +33433,257 @@ IF @Help = 1
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
';
+ /*Parameter info*/
+ SELECT N'@Help' AS [Parameter Name] ,
+ N'BIT' AS [Data Type] ,
+ N'0' AS [Default Value],
+ N'Displays this help message.' AS [Parameter Description]
+ UNION ALL
+ SELECT N'@DatabaseName',
+ N'NVARCHAR(128)',
+ N'NULL',
+ N'The name of the database you want to check the query store for.'
+ UNION ALL
+ SELECT N'@Top',
+ N'INT',
+ N'3',
+ N'The number of records to retrieve and analyze from the query store. The following system views are used: query_store_query, query_context_settings, query_store_wait_stats, query_store_runtime_stats,query_store_plan.'
+
+ UNION ALL
+ SELECT N'@StartDate',
+ N'DATETIME2(7)',
+ N'NULL',
+ N'Get query store info starting from this date. When not specified, sp_BlitzQueryStore gets info from the last 7 days'
+ UNION ALL
+ SELECT N'@EndDate',
+ N'DATETIME2(7)',
+ N'NULL',
+ N'Get query store info until this date. When not specified, sp_BlitzQueryStore gets info from the last 7 days'
+ UNION ALL
+ SELECT N'@MinimumExecutionCount',
+ N'INT',
+ N'NULL',
+ N'When a value is specified, sp_BlitzQueryStore gets info for queries where count_executions >= @MinimumExecutionCount'
+ UNION ALL
+ SELECT N'@DurationFilter',
+ N'DECIMAL(38,4)',
+ N'NULL',
+ N'Time unit - seconds. When a value is specified, sp_BlitzQueryStore gets info for queries where the average duration >= @DurationFilter'
+ UNION ALL
+ SELECT N'@StoredProcName',
+ N'NVARCHAR(128)',
+ N'NULL',
+ N'Get information for this specific stored procedure.'
+ UNION ALL
+ SELECT N'@Failed',
+ N'BIT',
+ N'0',
+ N'When set to 1, only information about failed queries is returned.'
+ UNION ALL
+ SELECT N'@PlanIdFilter',
+ N'INT',
+ N'NULL',
+ N'The ID of the plan you want to check for.'
+ UNION ALL
+ SELECT N'@QueryIdFilter',
+ N'INT',
+ N'NULL',
+ N'The ID of the query you want to check for.'
+ UNION ALL
+ SELECT N'@ExportToExcel',
+ N'BIT',
+ N'0',
+ N'When set to 1, prepares 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'@HideSummary',
+ N'BIT',
+ N'0',
+ N'When set to 1, hides the findings summary result set.'
+ UNION ALL
+ SELECT N'@SkipXML',
+ N'BIT',
+ N'0',
+ N'When set to 1, missing_indexes, implicit_conversion_info, cached_execution_parameters, are not returned. Does not affect query_plan_xml'
+ UNION ALL
+ SELECT N'@Debug',
+ N'BIT',
+ N'0',
+ N'Setting this to 1 will print dynamic SQL and select data from all tables used.'
+ UNION ALL
+ SELECT N'@ExpertMode',
+ N'BIT',
+ N'0',
+ N'When set to 1, more checks are done. Examples: many to many merge joins, row goals, adaptive joins, stats info, bad scans and plan forcing, computed columns that reference scalar UDFs.'
+ UNION ALL
+ SELECT N'@VersionCheckMode',
+ N'BIT',
+ N'0',
+ N'Outputs the version number and date.'
+
+ /* Column definitions */
+ SELECT 'database_name' AS [Column Name],
+ 'NVARCHAR(258)' AS [Data Type],
+ 'The name of the database where the plan was encountered.' AS [Column Description]
+ UNION ALL
+ SELECT 'query_cost',
+ 'FLOAT',
+ 'The cost of the execution plan in query bucks.'
+ UNION ALL
+ SELECT 'plan_id',
+ 'BIGINT',
+ 'The ID of the plan from sys.query_store_plan.'
+ UNION ALL
+ SELECT 'query_id',
+ 'BIGINT',
+ 'The ID of the query from sys.query_store_query.'
+ UNION ALL
+ SELECT 'query_id_all_plan_ids',
+ 'VARCHAR(8000)',
+ 'Comma-separated list of all query plan IDs associated with this query.'
+ UNION ALL
+ SELECT 'query_sql_text',
+ 'NVARCHAR(MAX)',
+ 'The text of the query, as provided by the user/app. Includes whitespaces, hints and comments. Comments and spaces before and after the query text are ignored.'
+ UNION ALL
+ SELECT 'proc_or_function_name',
+ 'NVARCHAR(258)',
+ 'If the query is part of a function/stored procedure, you''ll see here the name of its parent object.'
+ UNION ALL
+ SELECT 'query_plan_xml',
+ ' XML',
+ 'The query plan. Click to display a graphical plan.'
+ UNION ALL
+ SELECT 'warnings',
+ 'VARCHAR(MAX)',
+ 'A list of individual warnings generated by this query.'
+ UNION ALL
+ SELECT 'pattern',
+ 'NVARCHAR(512)',
+ 'A list of performance related patterns identified for this query.'
+ UNION ALL
+ SELECT 'parameter_sniffing_symptoms',
+ 'NVARCHAR(4000)',
+ 'A list of all the identified symptoms that are usually indicators of parameter sniffing.'
+ UNION ALL
+ SELECT 'last_force_failure_reason_desc',
+ 'NVARCHAR(258)',
+ 'Reason why plan forcing failed. NONE if plan isn''t forced.'
+ UNION ALL
+ SELECT 'top_three_waits',
+ 'NVARCHAR(MAX)',
+ 'The top 3 wait types, and their times in milliseconds, recorded for this query.'
+ UNION ALL
+ SELECT 'missing_indexes',
+ 'XML',
+ 'Missing index recommendations retrieved from the query plan.'
+ UNION ALL
+ SELECT 'implicit_conversion_info',
+ 'XML',
+ 'Information about the implicit conversion warnings,if any, retrieved from the query plan.'
+ UNION ALL
+ SELECT 'cached_execution_parameters',
+ 'XML',
+ 'Names, data types, and values for the parameters used when the query plan was compiled.'
+ UNION ALL
+ SELECT 'count_executions ',
+ 'BIGINT',
+ 'The number of executions of this particular query.'
+ UNION ALL
+ SELECT 'count_compiles',
+ 'BIGINT',
+ 'The number of plan compilations for this particular query.'
+ UNION ALL
+ SELECT 'total_cpu_time',
+ 'BIGINT',
+ 'Total CPU time, reported in milliseconds, that was consumed by all executions of this query.'
+ UNION ALL
+ SELECT 'avg_cpu_time ',
+ 'BIGINT',
+ 'Average CPU time, reported in milliseconds, consumed by each execution of this query.'
+ UNION ALL
+ SELECT 'total_duration',
+ 'BIGINT',
+ 'Total elapsed time, reported in milliseconds, consumed by all executions of this query.'
+ UNION ALL
+ SELECT 'avg_duration',
+ 'BIGINT',
+ 'Average elapsed time, reported in milliseconds, consumed by each execution of this query.'
+ UNION ALL
+ SELECT 'total_logical_io_reads',
+ 'BIGINT',
+ 'Total logical reads, reported in MB, performed by this query.'
+ UNION ALL
+ SELECT 'avg_logical_io_reads',
+ 'BIGINT',
+ 'Average logical reads, reported in MB, performed by each execution of this query.'
+ UNION ALL
+ SELECT 'total_physical_io_reads',
+ 'BIGINT',
+ 'Total physical reads, reported in MB, performed by this query.'
+ UNION ALL
+ SELECT 'avg_physical_io_reads',
+ 'BIGINT',
+ 'Average physical reads, reported in MB, performed by each execution of this query.'
+ UNION ALL
+ SELECT 'total_logical_io_writes',
+ 'BIGINT',
+ 'Total logical writes, reported in MB, performed by this query.'
+ UNION ALL
+ SELECT 'avg_logical_io_writes',
+ 'BIGINT',
+ 'Average logical writes, reported in MB, performed by each execution of this query.'
+ UNION ALL
+ SELECT 'total_rowcount',
+ 'BIGINT',
+ 'Total number of rows returned for all executions of this query.'
+ UNION ALL
+ SELECT 'avg_rowcount',
+ 'BIGINT',
+ 'Average number of rows returned by each execution of this query.'
+ UNION ALL
+ SELECT 'total_query_max_used_memory',
+ 'DECIMAL(38,2)',
+ 'Total max memory grant, reported in MB, used by this query.'
+ UNION ALL
+ SELECT 'avg_query_max_used_memory',
+ 'DECIMAL(38,2)',
+ 'Average max memory grant, reported in MB, used by each execution of this query.'
+ UNION ALL
+ SELECT 'total_tempdb_space_used',
+ 'DECIMAL(38,2)',
+ 'Total tempdb space, reported in MB, used by this query.'
+ UNION ALL
+ SELECT 'avg_tempdb_space_used',
+ 'DECIMAL(38,2)',
+ 'Average tempdb space, reported in MB, used by each execution of this query.'
+ UNION ALL
+ SELECT 'total_log_bytes_used',
+ 'DECIMAL(38,2)',
+ 'Total number of bytes in the database log used by this query.'
+ UNION ALL
+ SELECT 'avg_log_bytes_used',
+ 'DECIMAL(38,2)',
+ 'Average number of bytes in the database log used by each execution of this query.'
+ UNION ALL
+ SELECT 'total_num_physical_io_reads',
+ 'DECIMAL(38,2)',
+ 'Total number of physical I/O reads performed by this query (expressed as a number of read I/O operations).'
+ UNION ALL
+ SELECT 'avg_num_physical_io_reads',
+ 'DECIMAL(38,2)',
+ 'Average number of physical I/O reads performed by each execution of this query (expressed as a number of read I/O operations).'
+ UNION ALL
+ SELECT 'first_execution_time',
+ 'DATETIME2',
+ 'First execution time for this query within the aggregation interval. This is the end time of the query execution.'
+ UNION ALL
+ SELECT 'last_execution_time',
+ 'DATETIME2',
+ 'Last execution time for this query within the aggregation interval. This is the end time of the query execution.'
+ UNION ALL
+ SELECT 'context_settings',
+ 'NVARCHAR(512)',
+ 'Contains information about context settings associated with this query.';
RETURN;
END;
@@ -39012,7 +39378,7 @@ BEGIN
SET STATISTICS XML OFF;
SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
- SELECT @Version = '8.17', @VersionDate = '20231010';
+ SELECT @Version = '8.18', @VersionDate = '20231222';
IF(@VersionCheckMode = 1)
BEGIN
@@ -40412,7 +40778,7 @@ SET STATISTICS XML OFF;
/*Versioning details*/
-SELECT @Version = '8.17', @VersionDate = '20231010';
+SELECT @Version = '8.18', @VersionDate = '20231222';
IF(@VersionCheckMode = 1)
BEGIN
@@ -42027,38 +42393,39 @@ GO
ALTER PROCEDURE [dbo].[sp_ineachdb]
-- mssqltips.com/sqlservertip/5694/execute-a-command-in-the-context-of-each-database-in-sql-server--part-2/
- @command nvarchar(max) = NULL,
- @replace_character nchar(1) = N'?',
- @print_dbname bit = 0,
- @select_dbname bit = 0,
- @print_command bit = 0,
- @print_command_only bit = 0,
- @suppress_quotename bit = 0, -- use with caution
- @system_only bit = 0,
- @user_only bit = 0,
- @name_pattern nvarchar(300) = N'%',
- @database_list nvarchar(max) = NULL,
- @exclude_pattern nvarchar(300) = NULL,
- @exclude_list nvarchar(max) = NULL,
- @recovery_model_desc nvarchar(120) = NULL,
- @compatibility_level tinyint = NULL,
- @state_desc nvarchar(120) = N'ONLINE',
- @is_read_only bit = 0,
- @is_auto_close_on bit = NULL,
- @is_auto_shrink_on bit = NULL,
- @is_broker_enabled bit = NULL,
- @user_access nvarchar(128) = NULL,
- @Help BIT = 0,
- @Version VARCHAR(30) = NULL OUTPUT,
- @VersionDate DATETIME = NULL OUTPUT,
- @VersionCheckMode BIT = 0
+ @command nvarchar(max) = NULL,
+ @replace_character nchar(1) = N'?',
+ @print_dbname bit = 0,
+ @select_dbname bit = 0,
+ @print_command bit = 0,
+ @print_command_only bit = 0,
+ @suppress_quotename bit = 0, -- use with caution
+ @system_only bit = 0,
+ @user_only bit = 0,
+ @name_pattern nvarchar(300) = N'%',
+ @database_list nvarchar(max) = NULL,
+ @exclude_pattern nvarchar(300) = NULL,
+ @exclude_list nvarchar(max) = NULL,
+ @recovery_model_desc nvarchar(120) = NULL,
+ @compatibility_level tinyint = NULL,
+ @state_desc nvarchar(120) = N'ONLINE',
+ @is_read_only bit = 0,
+ @is_auto_close_on bit = NULL,
+ @is_auto_shrink_on bit = NULL,
+ @is_broker_enabled bit = NULL,
+ @user_access nvarchar(128) = NULL,
+ @Help bit = 0,
+ @Version varchar(30) = NULL OUTPUT,
+ @VersionDate datetime = NULL OUTPUT,
+ @VersionCheckMode bit = 0,
+ @is_ag_writeable_copy bit = 0
-- WITH EXECUTE AS OWNER – maybe not a great idea, depending on the security of your system
AS
BEGIN
SET NOCOUNT ON;
SET STATISTICS XML OFF;
- SELECT @Version = '8.17', @VersionDate = '20231010';
+ SELECT @Version = '8.18', @VersionDate = '20231222';
IF(@VersionCheckMode = 1)
BEGIN
@@ -42300,6 +42667,22 @@ OPTION (MAXRECURSION 0);
AND ar.secondary_role_allow_connections = 0
AND ags.primary_replica <> @ServerName
);
+ /* Remove databases which are not the writeable copies in an AG. */
+ IF @is_ag_writeable_copy = 1
+ BEGIN
+ DELETE dbs FROM #ineachdb AS dbs
+ WHERE EXISTS
+ (
+ SELECT 1 FROM sys.dm_hadr_database_replica_states AS drs
+ INNER JOIN sys.availability_replicas AS ar
+ ON ar.replica_id = drs.replica_id
+ INNER JOIN sys.dm_hadr_availability_group_states AS ags
+ ON ags.group_id = ar.group_id
+ WHERE drs.database_id = dbs.id
+ AND drs.is_primary_replica <> 1
+ AND ags.primary_replica <> @ServerName
+ );
+ END
END
-- Well, if we deleted them all...
@@ -42404,6 +42787,8 @@ DELETE FROM dbo.SqlServerVersions;
INSERT INTO dbo.SqlServerVersions
(MajorVersionNumber, MinorVersionNumber, Branch, [Url], ReleaseDate, MainstreamSupportEndDate, ExtendedSupportEndDate, MajorVersionName, MinorVersionName)
VALUES
+ (16, 4095, 'CU10', 'https://support.microsoft.com/en-us/help/5031778', '2023-11-16', '2028-01-11', '2033-01-11', 'SQL Server 2022', 'Cumulative Update 10'),
+ (16, 4085, 'CU9', 'https://support.microsoft.com/en-us/help/5030731', '2023-10-12', '2028-01-11', '2033-01-11', 'SQL Server 2022', 'Cumulative Update 9'),
(16, 4075, 'CU8', 'https://support.microsoft.com/en-us/help/5029666', '2023-09-14', '2028-01-11', '2033-01-11', 'SQL Server 2022', 'Cumulative Update 8'),
(16, 4065, 'CU7', 'https://support.microsoft.com/en-us/help/5028743', '2023-08-10', '2028-01-11', '2033-01-11', 'SQL Server 2022', 'Cumulative Update 7'),
(16, 4055, 'CU6', 'https://support.microsoft.com/en-us/help/5027505', '2023-07-13', '2028-01-11', '2033-01-11', 'SQL Server 2022', 'Cumulative Update 6'),
@@ -42414,6 +42799,8 @@ VALUES
(16, 4003, 'CU1', 'https://support.microsoft.com/en-us/help/5022375', '2023-02-16', '2028-01-11', '2033-01-11', 'SQL Server 2022', 'Cumulative Update 1'),
(16, 1050, 'RTM GDR', 'https://support.microsoft.com/kb/5021522', '2023-02-14', '2028-01-11', '2033-01-11', 'SQL Server 2022 GDR', 'RTM'),
(16, 1000, 'RTM', '', '2022-11-15', '2028-01-11', '2033-01-11', 'SQL Server 2022', 'RTM'),
+ (15, 4345, 'CU24', 'https://support.microsoft.com/kb/5031908', '2023-12-14', '2025-01-07', '2030-01-08', 'SQL Server 2019', 'Cumulative Update 24'),
+ (15, 4335, 'CU23', 'https://support.microsoft.com/kb/5030333', '2023-10-12', '2025-01-07', '2030-01-08', 'SQL Server 2019', 'Cumulative Update 23'),
(15, 4322, 'CU22', 'https://support.microsoft.com/kb/5027702', '2023-08-14', '2025-01-07', '2030-01-08', 'SQL Server 2019', 'Cumulative Update 22'),
(15, 4316, 'CU21', 'https://support.microsoft.com/kb/5025808', '2023-06-15', '2025-01-07', '2030-01-08', 'SQL Server 2019', 'Cumulative Update 21'),
(15, 4312, 'CU20', 'https://support.microsoft.com/kb/5024276', '2023-04-13', '2025-01-07', '2030-01-08', 'SQL Server 2019', 'Cumulative Update 20'),
@@ -42441,6 +42828,7 @@ VALUES
(15, 4003, 'CU1', 'https://support.microsoft.com/en-us/help/4527376', '2020-01-07', '2025-01-07', '2030-01-08', 'SQL Server 2019', 'Cumulative Update 1 '),
(15, 2070, 'GDR', 'https://support.microsoft.com/en-us/help/4517790', '2019-11-04', '2025-01-07', '2030-01-08', 'SQL Server 2019', 'RTM GDR '),
(15, 2000, 'RTM ', '', '2019-11-04', '2025-01-07', '2030-01-08', 'SQL Server 2019', 'RTM '),
+ (14, 3465, 'RTM CU31 GDR', 'https://support.microsoft.com/kb/5029376', '2023-10-12', '2022-10-11', '2027-10-12', 'SQL Server 2017', 'RTM Cumulative Update 31 GDR'),
(14, 3460, 'RTM CU31 GDR', 'https://support.microsoft.com/kb/5021126', '2023-02-14', '2022-10-11', '2027-10-12', 'SQL Server 2017', 'RTM Cumulative Update 31 GDR'),
(14, 3456, 'RTM CU31', 'https://support.microsoft.com/en-us/help/5016884', '2022-09-20', '2022-10-11', '2027-10-12', 'SQL Server 2017', 'RTM Cumulative Update 31'),
(14, 3451, 'RTM CU30', 'https://support.microsoft.com/en-us/help/5013756', '2022-07-13', '2022-10-11', '2027-10-12', 'SQL Server 2017', 'RTM Cumulative Update 30'),
@@ -42838,7 +43226,7 @@ SET NOCOUNT ON;
SET STATISTICS XML OFF;
SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
-SELECT @Version = '8.17', @VersionDate = '20231010';
+SELECT @Version = '8.18', @VersionDate = '20231222';
IF(@VersionCheckMode = 1)
BEGIN
diff --git a/Install-Core-Blitz-No-Query-Store.sql b/Install-Core-Blitz-No-Query-Store.sql
index 04060a6c..58cd0519 100644
--- a/Install-Core-Blitz-No-Query-Store.sql
+++ b/Install-Core-Blitz-No-Query-Store.sql
@@ -38,7 +38,7 @@ AS
SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
- SELECT @Version = '8.17', @VersionDate = '20231010';
+ SELECT @Version = '8.18', @VersionDate = '20231222';
SET @OutputType = UPPER(@OutputType);
IF(@VersionCheckMode = 1)
@@ -196,14 +196,11 @@ AS
,@SkipXPFixedDrives bit = 0
,@SkipXPCMDShell bit = 0
,@SkipMaster bit = 0
- ,@SkipMSDB bit = 0
+ ,@SkipMSDB_objs bit = 0
+ ,@SkipMSDB_jobs bit = 0
,@SkipModel bit = 0
,@SkipTempDB bit = 0
,@SkipValidateLogins bit = 0
- /* Variables for check 211: */
- ,@powerScheme varchar(36)
- ,@cpu_speed_mhz int
- ,@cpu_speed_ghz decimal(18,2);
DECLARE
@db_perms table
@@ -278,38 +275,6 @@ AS
SET @SkipTrace = 1;
END; /*We need this permission to execute trace stuff, apparently*/
- IF ISNULL(@SkipXPRegRead, 0) != 1 /*If @SkipXPRegRead hasn't been set to 1 by the caller*/
- BEGIN
- BEGIN TRY
- /* Get power plan if set by group policy [Git Hub Issue #1620] */
- EXEC xp_regread @rootkey = N'HKEY_LOCAL_MACHINE',
- @key = N'SOFTWARE\Policies\Microsoft\Power\PowerSettings',
- @value_name = N'ActivePowerScheme',
- @value = @powerScheme OUTPUT,
- @no_output = N'no_output';
-
- IF @powerScheme IS NULL /* If power plan was not set by group policy, get local value [Git Hub Issue #1620]*/
- EXEC xp_regread @rootkey = N'HKEY_LOCAL_MACHINE',
- @key = N'SYSTEM\CurrentControlSet\Control\Power\User\PowerSchemes',
- @value_name = N'ActivePowerScheme',
- @value = @powerScheme OUTPUT;
-
- /* Get the cpu speed*/
- EXEC xp_regread @rootkey = N'HKEY_LOCAL_MACHINE',
- @key = N'HARDWARE\DESCRIPTION\System\CentralProcessor\0',
- @value_name = N'~MHz',
- @value = @cpu_speed_mhz OUTPUT;
-
- /* Convert the Megahertz to Gigahertz */
- SET @cpu_speed_ghz = CAST(CAST(@cpu_speed_mhz AS decimal) / 1000 AS decimal(18,2));
-
- SET @SkipXPRegRead = 0; /*We could execute xp_regread*/
- END TRY
- BEGIN CATCH
- SET @SkipXPRegRead = 1; /*We have don't have execute rights or xp_regread throws an error so skip it*/
- END CATCH;
- END; /*Need execute on xp_regread*/
-
IF NOT EXISTS
(
SELECT
@@ -379,7 +344,7 @@ AS
END;
END;
- IF ISNULL(@SkipMSDB, 0) != 1 /*If @SkipMSDB hasn't been set to 1 by the caller*/
+ IF ISNULL(@SkipMSDB_objs, 0) != 1 /*If @SkipMSDB_objs hasn't been set to 1 by the caller*/
BEGIN
IF EXISTS
(
@@ -395,16 +360,45 @@ AS
FROM msdb.sys.objects
)
BEGIN
- SET @SkipMSDB = 0; /*We have read permissions in the msdb database, and can view the objects*/
+ SET @SkipMSDB_objs = 0; /*We have read permissions in the msdb database, and can view the objects*/
END;
END TRY
BEGIN CATCH
- SET @SkipMSDB = 1; /*We have read permissions in the msdb database ... oh wait we got tricked, we can't view the objects*/
+ SET @SkipMSDB_objs = 1; /*We have read permissions in the msdb database ... oh wait we got tricked, we can't view the objects*/
END CATCH;
END;
ELSE
BEGIN
- SET @SkipMSDB = 1; /*We don't have read permissions in the msdb database*/
+ SET @SkipMSDB_objs = 1; /*We don't have read permissions in the msdb database*/
+ END;
+ END;
+
+ IF ISNULL(@SkipMSDB_jobs, 0) != 1 /*If @SkipMSDB_jobs hasn't been set to 1 by the caller*/
+ BEGIN
+ IF EXISTS
+ (
+ SELECT 1/0
+ FROM @db_perms
+ WHERE database_name = N'msdb'
+ )
+ BEGIN
+ BEGIN TRY
+ IF EXISTS
+ (
+ SELECT 1/0
+ FROM msdb.dbo.sysjobs
+ )
+ BEGIN
+ SET @SkipMSDB_jobs = 0; /*We have read permissions in the msdb database, and can view the objects*/
+ END;
+ END TRY
+ BEGIN CATCH
+ SET @SkipMSDB_jobs = 1; /*We have read permissions in the msdb database ... oh wait we got tricked, we can't view the objects*/
+ END CATCH;
+ END;
+ ELSE
+ BEGIN
+ SET @SkipMSDB_jobs = 1; /*We don't have read permissions in the msdb database*/
END;
END;
END;
@@ -576,17 +570,34 @@ AS
INSERT #SkipChecks (DatabaseName, CheckID, ServerName)
SELECT
v.*
- FROM (VALUES(NULL, 6, NULL), /*Jobs Owned By Users*/
- (NULL, 28, NULL), /*SQL Agent Job Runs at Startup*/
- (NULL, 57, NULL), /*Tables in the MSDB Database*/
+ FROM (VALUES(NULL, 28, NULL)) AS v (DatabaseName, CheckID, ServerName) /*Tables in the MSDB Database*/
+ WHERE @SkipMSDB_objs = 1;
+
+ INSERT #SkipChecks (DatabaseName, CheckID, ServerName)
+ SELECT
+ v.*
+ FROM (VALUES
+ /*sysjobs checks*/
+ (NULL, 6, NULL), /*Jobs Owned By Users*/
+ (NULL, 57, NULL), /*SQL Agent Job Runs at Startup*/
(NULL, 79, NULL), /*Shrink Database Job*/
(NULL, 94, NULL), /*Agent Jobs Without Failure Emails*/
(NULL, 123, NULL), /*Agent Jobs Starting Simultaneously*/
(NULL, 180, NULL), /*Shrink Database Step In Maintenance Plan*/
(NULL, 181, NULL), /*Repetitive Maintenance Tasks*/
- (NULL, 219, NULL) /*Alerts Without Event Descriptions*/
- ) AS v (DatabaseName, CheckID, ServerName)
- WHERE @SkipMSDB = 1;
+
+ /*sysalerts checks*/
+ (NULL, 30, NULL), /*Not All Alerts Configured*/
+ (NULL, 59, NULL), /*Alerts Configured without Follow Up*/
+ (NULL, 61, NULL), /*No Alerts for Sev 19-25*/
+ (NULL, 96, NULL), /*No Alerts for Corruption*/
+ (NULL, 98, NULL), /*Alerts Disabled*/
+ (NULL, 219, NULL), /*Alerts Without Event Descriptions*/
+
+ /*sysoperators*/
+ (NULL, 31, NULL) /*No Operators Configured/Enabled*/
+ ) AS v (DatabaseName, CheckID, ServerName)
+ WHERE @SkipMSDB_jobs = 1;
INSERT #SkipChecks (DatabaseName, CheckID, ServerName)
SELECT
@@ -630,6 +641,25 @@ AS
FROM (VALUES(NULL, 2301, NULL)) AS v (DatabaseName, CheckID, ServerName) /*sp_validatelogins*/
WHERE @SkipValidateLogins = 1
+ IF @sa = 0
+ BEGIN
+ INSERT INTO #BlitzResults
+ ( CheckID ,
+ Priority ,
+ FindingsGroup ,
+ Finding ,
+ URL ,
+ Details
+ )
+ SELECT 223 AS CheckID ,
+ 0 AS Priority ,
+ 'Informational' AS FindingsGroup ,
+ 'Some Checks Skipped' AS Finding ,
+ '' AS URL ,
+ 'User ''' + @SUSER_NAME + ''' is not part of the sysadmin role, so we skipped some checks that are not possible due to lack of permissions.' AS Details;
+ END;
+ /*End of SkipsChecks added due to permissions*/
+
IF @SkipChecksTable IS NOT NULL
AND @SkipChecksSchema IS NOT NULL
AND @SkipChecksDatabase IS NOT NULL
@@ -8674,122 +8704,147 @@ IF @ProductVersionMajor >= 10 AND NOT EXISTS ( SELECT 1
EXECUTE(@StringToExecute);
END;
- /*
- Starting with SQL Server 2014 SP2, Instant File Initialization
- is logged in the SQL Server Error Log.
- */
- IF NOT EXISTS ( SELECT 1
- FROM #SkipChecks
- WHERE DatabaseName IS NULL AND CheckID = 193 )
- AND ((@ProductVersionMajor >= 13) OR (@ProductVersionMajor = 12 AND @ProductVersionMinor >= 5000))
+ /* Performance - Instant File Initialization Not Enabled - Check 192 */
+ /* Server Info - Instant File Initialization Enabled - Check 193 */
+ IF NOT EXISTS ( SELECT 1/0
+ FROM #SkipChecks
+ WHERE DatabaseName IS NULL AND CheckID = 192 /* IFI disabled check disabled */
+ ) OR NOT EXISTS
+ ( SELECT 1/0
+ FROM #SkipChecks
+ WHERE DatabaseName IS NULL AND CheckID = 193 /* IFI enabled check disabled */
+ )
+ BEGIN
+ IF @Debug IN (1, 2) RAISERROR('Running CheckId [%d] and CheckId [%d].', 0, 1, 192, 193) WITH NOWAIT;
+
+ DECLARE @IFISetting varchar(1) = N'N'
+ ,@IFIReadDMVFailed bit = 0
+ ,@IFIAllFailed bit = 0;
+
+ /* See if we can get the instant_file_initialization_enabled column from sys.dm_server_services */
+ IF EXISTS
+ (
+ SELECT 1/0
+ FROM sys.all_columns
+ WHERE [object_id] = OBJECT_ID(N'[sys].[dm_server_services]')
+ AND [name] = N'instant_file_initialization_enabled'
+ )
BEGIN
+ /* This needs to be a "dynamic" SQL statement because if the 'instant_file_initialization_enabled' column doesn't exist the procedure might fail on a bind error */
+ SET @StringToExecute = N'SELECT @IFISetting = instant_file_initialization_enabled' + @crlf +
+ N'FROM sys.dm_server_services' + @crlf +
+ N'WHERE filename LIKE ''%sqlservr.exe%''' + @crlf +
+ N'OPTION (RECOMPILE);';
+
+ IF @Debug = 2 AND @StringToExecute IS NOT NULL PRINT @StringToExecute;
+ IF @Debug = 2 AND @StringToExecute IS NULL PRINT '@StringToExecute has gone NULL, for some reason.';
+
+ EXEC dbo.sp_executesql
+ @StringToExecute
+ ,N'@IFISetting varchar(1) OUTPUT'
+ ,@IFISetting = @IFISetting OUTPUT
- IF @Debug IN (1, 2) RAISERROR('Running CheckId [%d].', 0, 1, 193) WITH NOWAIT;
-
- -- If this is Amazon RDS, use rdsadmin.dbo.rds_read_error_log
- IF LEFT(CAST(SERVERPROPERTY('ComputerNamePhysicalNetBIOS') AS VARCHAR(8000)), 8) = 'EC2AMAZ-'
- AND LEFT(CAST(SERVERPROPERTY('MachineName') AS VARCHAR(8000)), 8) = 'EC2AMAZ-'
- AND db_id('rdsadmin') IS NOT NULL
- AND EXISTS(SELECT * FROM master.sys.all_objects WHERE name IN ('rds_startup_tasks', 'rds_help_revlogin', 'rds_hexadecimal', 'rds_failover_tracking', 'rds_database_tracking', 'rds_track_change'))
- BEGIN
- INSERT INTO #ErrorLog
- EXEC rdsadmin.dbo.rds_read_error_log 0, 1, N'Database Instant File Initialization: enabled';
- END
- ELSE
- BEGIN
- BEGIN TRY
- INSERT INTO #ErrorLog
- EXEC sys.xp_readerrorlog 0, 1, N'Database Instant File Initialization: enabled';
- END TRY
- BEGIN CATCH
- IF @Debug IN (1, 2) RAISERROR('No permissions to execute xp_readerrorlog.', 0, 1) WITH NOWAIT;
- END CATCH
- END
+ SET @IFIReadDMVFailed = 0;
+ END
+ ELSE
+ /* We couldn't get the instant_file_initialization_enabled column from sys.dm_server_services, fall back to read error log */
+ BEGIN
+ SET @IFIReadDMVFailed = 1;
+ /* If this is Amazon RDS, we'll use the rdsadmin.dbo.rds_read_error_log */
+ IF LEFT(CAST(SERVERPROPERTY('ComputerNamePhysicalNetBIOS') AS VARCHAR(8000)), 8) = 'EC2AMAZ-'
+ AND LEFT(CAST(SERVERPROPERTY('MachineName') AS VARCHAR(8000)), 8) = 'EC2AMAZ-'
+ AND db_id('rdsadmin') IS NOT NULL
+ AND EXISTS ( SELECT 1/0
+ FROM master.sys.all_objects
+ WHERE name IN ('rds_startup_tasks', 'rds_help_revlogin', 'rds_hexadecimal', 'rds_failover_tracking', 'rds_database_tracking', 'rds_track_change')
+ )
+ BEGIN
+ /* Amazon RDS detected, read rdsadmin.dbo.rds_read_error_log */
+ INSERT INTO #ErrorLog
+ EXEC rdsadmin.dbo.rds_read_error_log 0, 1, N'Database Instant File Initialization: enabled';
+ END
+ ELSE
+ BEGIN
+ /* Try to read the error log, this might fail due to permissions */
+ BEGIN TRY
+ INSERT INTO #ErrorLog
+ EXEC sys.xp_readerrorlog 0, 1, N'Database Instant File Initialization: enabled';
+ END TRY
+ BEGIN CATCH
+ IF @Debug IN (1, 2) RAISERROR('No permissions to execute xp_readerrorlog.', 0, 1) WITH NOWAIT;
+ SET @IFIAllFailed = 1;
+ END CATCH
+ END;
+ END;
+
+ IF @IFIAllFailed = 0
+ BEGIN
+ IF @IFIReadDMVFailed = 1
+ /* We couldn't read the DMV so set the @IFISetting variable using the error log */
+ BEGIN
+ IF EXISTS ( SELECT 1/0
+ FROM #ErrorLog
+ WHERE LEFT([Text], 45) = N'Database Instant File Initialization: enabled'
+ )
+ BEGIN
+ SET @IFISetting = 'Y';
+ END
+ ELSE
+ BEGIN
+ SET @IFISetting = 'N';
+ END;
+ END;
+
+ IF NOT EXISTS ( SELECT 1/0
+ FROM #SkipChecks
+ WHERE DatabaseName IS NULL AND CheckID = 192 /* IFI disabled check disabled */
+ ) AND @IFISetting = 'N'
+ BEGIN
+ INSERT INTO #BlitzResults
+ (
+ CheckID ,
+ [Priority] ,
+ FindingsGroup ,
+ Finding ,
+ URL ,
+ Details
+ )
+ SELECT
+ 192 AS [CheckID] ,
+ 50 AS [Priority] ,
+ 'Performance' AS [FindingsGroup] ,
+ 'Instant File Initialization Not Enabled' AS [Finding] ,
+ 'https://www.brentozar.com/go/instant' AS [URL] ,
+ 'Consider enabling IFI for faster restores and data file growths.' AS [Details]
+ END;
+
+ IF NOT EXISTS ( SELECT 1/0
+ FROM #SkipChecks
+ WHERE DatabaseName IS NULL AND CheckID = 193 /* IFI enabled check disabled */
+ ) AND @IFISetting = 'Y'
+ BEGIN
+ INSERT INTO #BlitzResults
+ (
+ CheckID ,
+ [Priority] ,
+ FindingsGroup ,
+ Finding ,
+ URL ,
+ Details
+ )
+ SELECT
+ 193 AS [CheckID] ,
+ 250 AS [Priority] ,
+ 'Server Info' AS [FindingsGroup] ,
+ 'Instant File Initialization Enabled' AS [Finding] ,
+ 'https://www.brentozar.com/go/instant' AS [URL] ,
+ 'The service account has the Perform Volume Maintenance Tasks permission.' AS [Details]
+ END;
+ END;
+ END;
- IF EXISTS
- (
- SELECT 1/0
- FROM #ErrorLog
- WHERE LEFT([Text], 45) = N'Database Instant File Initialization: enabled'
- )
- BEGIN
- INSERT INTO #BlitzResults
- ( CheckID ,
- [Priority] ,
- FindingsGroup ,
- Finding ,
- URL ,
- Details
- )
- SELECT
- 193 AS [CheckID] ,
- 250 AS [Priority] ,
- 'Server Info' AS [FindingsGroup] ,
- 'Instant File Initialization Enabled' AS [Finding] ,
- 'https://www.brentozar.com/go/instant' AS [URL] ,
- 'The service account has the Perform Volume Maintenance Tasks permission.';
- END;
- else -- if version of sql server has instant_file_initialization_enabled column in dm_server_services, check that too
- -- in the event the error log has been cycled and the startup messages are not in the current error log
- begin
- 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_server_services'
- AND c.name = 'instant_file_initialization_enabled' )
- begin
- SET @StringToExecute = N'
- INSERT INTO #BlitzResults
- ( CheckID ,
- [Priority] ,
- FindingsGroup ,
- Finding ,
- URL ,
- Details
- )
- SELECT
- 193 AS [CheckID] ,
- 250 AS [Priority] ,
- ''Server Info'' AS [FindingsGroup] ,
- ''Instant File Initialization Enabled'' AS [Finding] ,
- ''https://www.brentozar.com/go/instant'' AS [URL] ,
- ''The service account has the Perform Volume Maintenance Tasks permission.''
- where exists (select 1 FROM sys.dm_server_services
- WHERE instant_file_initialization_enabled = ''Y''
- AND filename LIKE ''%sqlservr.exe%'')
- OPTION (RECOMPILE);';
- EXEC(@StringToExecute);
- end;
- end;
- END;
-
- /* Server Info - Instant File Initialization Not Enabled - Check 192 - SQL Server 2016 SP1 and newer */
- IF NOT EXISTS ( SELECT 1
- FROM #SkipChecks
- WHERE DatabaseName IS NULL AND CheckID = 192 )
- AND EXISTS ( SELECT *
- FROM sys.all_objects o
- INNER JOIN sys.all_columns c ON o.object_id = c.object_id
- WHERE o.name = 'dm_server_services'
- AND c.name = 'instant_file_initialization_enabled' )
- BEGIN
-
- IF @Debug IN (1, 2) RAISERROR('Running CheckId [%d].', 0, 1, 192) WITH NOWAIT;
-
- SET @StringToExecute = 'INSERT INTO #BlitzResults (CheckID, Priority, FindingsGroup, Finding, URL, Details)
- SELECT 192 AS CheckID ,
- 50 AS Priority ,
- ''Server Info'' AS FindingsGroup ,
- ''Instant File Initialization Not Enabled'' AS Finding ,
- ''https://www.brentozar.com/go/instant'' AS URL ,
- ''Consider enabling IFI for faster restores and data file growths.''
- FROM sys.dm_server_services WHERE instant_file_initialization_enabled <> ''Y'' AND filename LIKE ''%sqlservr.exe%'' OPTION (RECOMPILE);';
-
- IF @Debug = 2 AND @StringToExecute IS NOT NULL PRINT @StringToExecute;
- IF @Debug = 2 AND @StringToExecute IS NULL PRINT '@StringToExecute has gone NULL, for some reason.';
-
- EXECUTE(@StringToExecute);
- END;
+ /* End of checkId 192 */
+ /* End of checkId 193 */
IF NOT EXISTS ( SELECT 1
FROM #SkipChecks
@@ -9167,7 +9222,39 @@ IF @ProductVersionMajor >= 10 AND NOT EXISTS ( SELECT 1
WHERE DatabaseName IS NULL AND CheckID = 211 )
BEGIN
+ /* Variables for check 211: */
+ DECLARE
+ @powerScheme varchar(36)
+ ,@cpu_speed_mhz int
+ ,@cpu_speed_ghz decimal(18,2)
+ ,@ExecResult int;
+
IF @Debug IN (1, 2) RAISERROR('Running CheckId [%d].', 0, 1, 211) WITH NOWAIT;
+ IF @sa = 0 RAISERROR('The errors: ''xp_regread() returned error 5, ''Access is denied.'''' can be safely ignored', 0, 1) WITH NOWAIT;
+
+ /* Get power plan if set by group policy [Git Hub Issue #1620] */
+ EXEC xp_regread @rootkey = N'HKEY_LOCAL_MACHINE',
+ @key = N'SOFTWARE\Policies\Microsoft\Power\PowerSettings',
+ @value_name = N'ActivePowerScheme',
+ @value = @powerScheme OUTPUT,
+ @no_output = N'no_output';
+
+ IF @powerScheme IS NULL /* If power plan was not set by group policy, get local value [Git Hub Issue #1620]*/
+ EXEC xp_regread @rootkey = N'HKEY_LOCAL_MACHINE',
+ @key = N'SYSTEM\CurrentControlSet\Control\Power\User\PowerSchemes',
+ @value_name = N'ActivePowerScheme',
+ @value = @powerScheme OUTPUT;
+
+ /* Get the cpu speed*/
+ EXEC @ExecResult = xp_regread @rootkey = N'HKEY_LOCAL_MACHINE',
+ @key = N'HARDWARE\DESCRIPTION\System\CentralProcessor\0',
+ @value_name = N'~MHz',
+ @value = @cpu_speed_mhz OUTPUT;
+
+ /* Convert the Megahertz to Gigahertz */
+ IF @ExecResult != 0 RAISERROR('We couldn''t retrieve the CPU speed, you will see Unknown in the results', 0, 1)
+
+ SET @cpu_speed_ghz = CAST(CAST(@cpu_speed_mhz AS decimal) / 1000 AS decimal(18,2));
INSERT INTO #BlitzResults
( CheckID ,
@@ -9183,7 +9270,7 @@ IF @ProductVersionMajor >= 10 AND NOT EXISTS ( SELECT 1
'Power Plan' AS Finding,
'https://www.brentozar.com/blitz/power-mode/' AS URL,
'Your server has '
- + CAST(@cpu_speed_ghz as VARCHAR(4))
+ + ISNULL(CAST(@cpu_speed_ghz as VARCHAR(8)), 'Unknown ')
+ 'GHz CPUs, and is in '
+ CASE @powerScheme
WHEN 'a1841308-3541-4fab-bc81-f71556f20b4a'
@@ -9839,20 +9926,22 @@ IF @ProductVersionMajor >= 10 AND NOT EXISTS ( SELECT 1
FROM #BlitzResults
WHERE Priority > 0 AND Priority < 255 AND FindingsGroup IS NOT NULL AND Finding IS NOT NULL
AND FindingsGroup <> 'Security' /* Specifically excluding security checks for public exports */)
- SELECT
- CASE
- WHEN r.Priority <> COALESCE(rPrior.Priority, 0) OR r.FindingsGroup <> rPrior.FindingsGroup THEN @crlf + N'**Priority ' + CAST(COALESCE(r.Priority,N'') AS NVARCHAR(5)) + N': ' + COALESCE(r.FindingsGroup,N'') + N'**:' + @crlf + @crlf
- ELSE N''
- END
- + CASE WHEN r.Finding <> COALESCE(rPrior.Finding,N'') AND r.Finding <> COALESCE(rNext.Finding,N'') THEN N'- ' + COALESCE(r.Finding,N'') + N' ' + COALESCE(r.DatabaseName, N'') + N' - ' + COALESCE(r.Details,N'') + @crlf
- WHEN r.Finding <> COALESCE(rPrior.Finding,N'') AND r.Finding = rNext.Finding AND r.Details = rNext.Details THEN N'- ' + COALESCE(r.Finding,N'') + N' - ' + COALESCE(r.Details,N'') + @crlf + @crlf + N' * ' + COALESCE(r.DatabaseName, N'') + @crlf
- WHEN r.Finding <> COALESCE(rPrior.Finding,N'') AND r.Finding = rNext.Finding THEN N'- ' + COALESCE(r.Finding,N'') + @crlf + CASE WHEN r.DatabaseName IS NULL THEN N'' ELSE N' * ' + COALESCE(r.DatabaseName,N'') END + CASE WHEN r.Details <> rPrior.Details THEN N' - ' + COALESCE(r.Details,N'') + @crlf ELSE '' END
- ELSE CASE WHEN r.DatabaseName IS NULL THEN N'' ELSE N' * ' + COALESCE(r.DatabaseName,N'') END + CASE WHEN r.Details <> rPrior.Details THEN N' - ' + COALESCE(r.Details,N'') + @crlf ELSE N'' + @crlf END
- END + @crlf
- FROM Results r
- LEFT OUTER JOIN Results rPrior ON r.rownum = rPrior.rownum + 1
- LEFT OUTER JOIN Results rNext ON r.rownum = rNext.rownum - 1
- ORDER BY r.rownum FOR XML PATH(N'');
+ SELECT
+ Markdown = CONVERT(XML, STUFF((SELECT
+ CASE
+ WHEN r.Priority <> COALESCE(rPrior.Priority, 0) OR r.FindingsGroup <> rPrior.FindingsGroup THEN @crlf + N'**Priority ' + CAST(COALESCE(r.Priority,N'') AS NVARCHAR(5)) + N': ' + COALESCE(r.FindingsGroup,N'') + N'**:' + @crlf + @crlf
+ ELSE N''
+ END
+ + CASE WHEN r.Finding <> COALESCE(rPrior.Finding,N'') AND r.Finding <> COALESCE(rNext.Finding,N'') THEN N'- ' + COALESCE(r.Finding,N'') + N' ' + COALESCE(r.DatabaseName, N'') + N' - ' + COALESCE(r.Details,N'') + @crlf
+ WHEN r.Finding <> COALESCE(rPrior.Finding,N'') AND r.Finding = rNext.Finding AND r.Details = rNext.Details THEN N'- ' + COALESCE(r.Finding,N'') + N' - ' + COALESCE(r.Details,N'') + @crlf + @crlf + N' * ' + COALESCE(r.DatabaseName, N'') + @crlf
+ WHEN r.Finding <> COALESCE(rPrior.Finding,N'') AND r.Finding = rNext.Finding THEN N'- ' + COALESCE(r.Finding,N'') + @crlf + @crlf + CASE WHEN r.DatabaseName IS NULL THEN N'' ELSE N' * ' + COALESCE(r.DatabaseName,N'') END + CASE WHEN r.Details <> rPrior.Details THEN N' - ' + COALESCE(r.Details,N'') + @crlf ELSE '' END
+ ELSE CASE WHEN r.DatabaseName IS NULL THEN N'' ELSE N' * ' + COALESCE(r.DatabaseName,N'') END + CASE WHEN r.Details <> rPrior.Details THEN N' - ' + COALESCE(r.Details,N'') + @crlf ELSE N'' + @crlf END
+ END + @crlf
+ FROM Results r
+ LEFT OUTER JOIN Results rPrior ON r.rownum = rPrior.rownum + 1
+ LEFT OUTER JOIN Results rNext ON r.rownum = rNext.rownum - 1
+ ORDER BY r.rownum FOR XML PATH(N''), ROOT('Markdown'), TYPE).value('/Markdown[1]','VARCHAR(MAX)'), 1, 2, '')
+ + '');
END;
ELSE IF @OutputType = 'XML'
BEGIN
@@ -10016,7 +10105,7 @@ AS
SET NOCOUNT ON;
SET STATISTICS XML OFF;
-SELECT @Version = '8.17', @VersionDate = '20231010';
+SELECT @Version = '8.18', @VersionDate = '20231222';
IF(@VersionCheckMode = 1)
BEGIN
@@ -10894,7 +10983,7 @@ AS
SET STATISTICS XML OFF;
SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
- SELECT @Version = '8.17', @VersionDate = '20231010';
+ SELECT @Version = '8.18', @VersionDate = '20231222';
IF(@VersionCheckMode = 1)
BEGIN
@@ -12676,7 +12765,7 @@ SET NOCOUNT ON;
SET STATISTICS XML OFF;
SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
-SELECT @Version = '8.17', @VersionDate = '20231010';
+SELECT @Version = '8.18', @VersionDate = '20231222';
SET @OutputType = UPPER(@OutputType);
IF(@VersionCheckMode = 1)
@@ -19733,16 +19822,16 @@ END ';
IF @Debug = 1
BEGIN
- PRINT SUBSTRING(@StringToExecute, 0, 4000);
- PRINT SUBSTRING(@StringToExecute, 4000, 8000);
- PRINT SUBSTRING(@StringToExecute, 8000, 12000);
- PRINT SUBSTRING(@StringToExecute, 12000, 16000);
- PRINT SUBSTRING(@StringToExecute, 16000, 20000);
- PRINT SUBSTRING(@StringToExecute, 20000, 24000);
- PRINT SUBSTRING(@StringToExecute, 24000, 28000);
- PRINT SUBSTRING(@StringToExecute, 28000, 32000);
- PRINT SUBSTRING(@StringToExecute, 32000, 36000);
- PRINT SUBSTRING(@StringToExecute, 36000, 40000);
+ PRINT SUBSTRING(@StringToExecute, 1, 4000);
+ PRINT SUBSTRING(@StringToExecute, 4001, 4000);
+ PRINT SUBSTRING(@StringToExecute, 8001, 4000);
+ PRINT SUBSTRING(@StringToExecute, 12001, 4000);
+ PRINT SUBSTRING(@StringToExecute, 16001, 4000);
+ PRINT SUBSTRING(@StringToExecute, 20001, 4000);
+ PRINT SUBSTRING(@StringToExecute, 24001, 4000);
+ PRINT SUBSTRING(@StringToExecute, 28001, 4000);
+ PRINT SUBSTRING(@StringToExecute, 32001, 4000);
+ PRINT SUBSTRING(@StringToExecute, 36001, 4000);
END;
EXEC sp_executesql @StringToExecute, N'@Top INT, @min_duration INT, @min_back INT, @CheckDateOverride DATETIMEOFFSET, @MinimumExecutionCount INT', @Top, @DurationFilter_i, @MinutesBack, @CheckDateOverride, @MinimumExecutionCount;
@@ -20035,7 +20124,7 @@ SET NOCOUNT ON;
SET STATISTICS XML OFF;
SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
-SELECT @Version = '8.17', @VersionDate = '20231010';
+SELECT @Version = '8.18', @VersionDate = '20231222';
SET @OutputType = UPPER(@OutputType);
IF(@VersionCheckMode = 1)
@@ -21201,16 +21290,16 @@ BEGIN TRY
RAISERROR (N'Inserting data into #IndexColumns for clustered indexes and heaps',0,1) WITH NOWAIT;
IF @Debug = 1
BEGIN
- PRINT SUBSTRING(@dsql, 0, 4000);
- PRINT SUBSTRING(@dsql, 4000, 8000);
- PRINT SUBSTRING(@dsql, 8000, 12000);
- PRINT SUBSTRING(@dsql, 12000, 16000);
- PRINT SUBSTRING(@dsql, 16000, 20000);
- PRINT SUBSTRING(@dsql, 20000, 24000);
- PRINT SUBSTRING(@dsql, 24000, 28000);
- PRINT SUBSTRING(@dsql, 28000, 32000);
- PRINT SUBSTRING(@dsql, 32000, 36000);
- PRINT SUBSTRING(@dsql, 36000, 40000);
+ PRINT SUBSTRING(@dsql, 1, 4000);
+ PRINT SUBSTRING(@dsql, 4001, 4000);
+ PRINT SUBSTRING(@dsql, 8001, 4000);
+ PRINT SUBSTRING(@dsql, 12001, 4000);
+ PRINT SUBSTRING(@dsql, 16001, 4000);
+ PRINT SUBSTRING(@dsql, 20001, 4000);
+ PRINT SUBSTRING(@dsql, 24001, 4000);
+ PRINT SUBSTRING(@dsql, 28001, 4000);
+ PRINT SUBSTRING(@dsql, 32001, 4000);
+ PRINT SUBSTRING(@dsql, 36001, 4000);
END;
BEGIN TRY
INSERT #IndexColumns ( database_id, [schema_name], [object_id], index_id, key_ordinal, is_included_column, is_descending_key, partition_ordinal,
@@ -22578,6 +22667,7 @@ SELECT
FROM #IndexSanity;
RAISERROR (N'Populate #PartitionCompressionInfo.',0,1) WITH NOWAIT;
+IF OBJECT_ID('tempdb..#maps') IS NOT NULL DROP TABLE #maps;
WITH maps
AS
(
@@ -22592,6 +22682,7 @@ SELECT *
INTO #maps
FROM maps;
+IF OBJECT_ID('tempdb..#grps') IS NOT NULL DROP TABLE #grps;
WITH grps
AS
(
@@ -26217,10 +26308,11 @@ WITH RECOMPILE
AS
BEGIN
SET STATISTICS XML OFF;
- SET NOCOUNT, XACT_ABORT ON;
+ SET NOCOUNT ON;
+ SET XACT_ABORT OFF;
SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
- SELECT @Version = '8.17', @VersionDate = '20231010';
+ SELECT @Version = '8.18', @VersionDate = '20231222';
IF @VersionCheckMode = 1
BEGIN
@@ -26344,6 +26436,20 @@ BEGIN
THEN 1
ELSE 0
END,
+ @MI bit =
+ CASE
+ WHEN
+ (
+ SELECT
+ CONVERT
+ (
+ integer,
+ SERVERPROPERTY('EngineEdition')
+ )
+ ) = 8
+ THEN 1
+ ELSE 0
+ END,
@RDS bit =
CASE
WHEN LEFT(CAST(SERVERPROPERTY('ComputerNamePhysicalNetBIOS') AS varchar(8000)), 8) <> 'EC2AMAZ-'
@@ -26482,6 +26588,17 @@ BEGIN
@StartDateUTC = @StartDate,
@EndDateUTC = @EndDate;
+ IF
+ (
+ @MI = 1
+ AND @EventSessionName = N'system_health'
+ AND @TargetSessionType IS NULL
+ )
+ BEGIN
+ SET
+ @TargetSessionType = N'ring_buffer';
+ END;
+
IF @Azure = 0
BEGIN
IF NOT EXISTS
@@ -26499,7 +26616,7 @@ BEGIN
RETURN;
END;
END;
-
+
IF @Azure = 1
BEGIN
IF NOT EXISTS
@@ -28029,7 +28146,7 @@ BEGIN
COUNT_BIG(DISTINCT dp.event_date)
) +
N' deadlocks.',
- sort_order =
+ sort_order =
ROW_NUMBER()
OVER (ORDER BY COUNT_BIG(DISTINCT dp.event_date) DESC)
FROM #deadlock_process AS dp
@@ -28069,7 +28186,7 @@ BEGIN
SELECT
1/0
FROM sys.databases AS d
- WHERE d.name = dow.database_name
+ WHERE d.name COLLATE DATABASE_DEFAULT = dow.database_name COLLATE DATABASE_DEFAULT
AND d.is_read_committed_snapshot_on = 1
)
THEN N'You already enabled RCSI, but...'
@@ -28084,7 +28201,7 @@ BEGIN
COUNT_BIG(DISTINCT dow.event_date)
) +
N' deadlock(s) between read queries and modification queries.',
- sort_order =
+ sort_order =
ROW_NUMBER()
OVER (ORDER BY COUNT_BIG(DISTINCT dow.event_date) DESC)
FROM #deadlock_owner_waiter AS dow
@@ -28146,7 +28263,7 @@ BEGIN
COUNT_BIG(DISTINCT dow.event_date)
) +
N' deadlock(s).',
- sort_order =
+ sort_order =
ROW_NUMBER()
OVER (ORDER BY COUNT_BIG(DISTINCT dow.event_date) DESC)
FROM #deadlock_owner_waiter AS dow
@@ -28189,7 +28306,7 @@ BEGIN
COUNT_BIG(DISTINCT dow.event_date)
) +
N' deadlock(s).',
- sort_order =
+ sort_order =
ROW_NUMBER()
OVER (ORDER BY COUNT_BIG(DISTINCT dow.event_date) DESC)
FROM #deadlock_owner_waiter AS dow
@@ -28238,7 +28355,7 @@ BEGIN
COUNT_BIG(DISTINCT dow.event_date)
) +
N' deadlock(s).',
- sort_order =
+ sort_order =
ROW_NUMBER()
OVER (ORDER BY COUNT_BIG(DISTINCT dow.event_date) DESC)
FROM #deadlock_owner_waiter AS dow
@@ -28287,7 +28404,7 @@ BEGIN
COUNT_BIG(DISTINCT dp.event_date)
) +
N' instances of Serializable deadlocks.',
- sort_order =
+ sort_order =
ROW_NUMBER()
OVER (ORDER BY COUNT_BIG(DISTINCT dp.event_date) DESC)
FROM #deadlock_process AS dp
@@ -28330,7 +28447,7 @@ BEGIN
COUNT_BIG(DISTINCT dp.event_date)
) +
N' instances of Repeatable Read deadlocks.',
- sort_order =
+ sort_order =
ROW_NUMBER()
OVER (ORDER BY COUNT_BIG(DISTINCT dp.event_date) DESC)
FROM #deadlock_process AS dp
@@ -28392,7 +28509,7 @@ BEGIN
N'UNKNOWN'
) +
N'.',
- sort_order =
+ sort_order =
ROW_NUMBER()
OVER (ORDER BY COUNT_BIG(DISTINCT dp.event_date) DESC)
FROM #deadlock_process AS dp
@@ -28504,7 +28621,7 @@ BEGIN
1,
N''
) + N' locks.',
- sort_order =
+ sort_order =
ROW_NUMBER()
OVER (ORDER BY CONVERT(bigint, lt.lock_count) DESC)
FROM lock_types AS lt
@@ -28683,7 +28800,7 @@ BEGIN
COUNT_BIG(DISTINCT ds.id)
) +
N' deadlocks.',
- sort_order =
+ sort_order =
ROW_NUMBER()
OVER (ORDER BY COUNT_BIG(DISTINCT ds.id) DESC)
FROM #deadlock_stack AS ds
@@ -28784,19 +28901,19 @@ BEGIN
)
),
wait_time_hms =
- /*the more wait time you rack up the less accurate this gets,
+ /*the more wait time you rack up the less accurate this gets,
it's either that or erroring out*/
- CASE
- WHEN
+ CASE
+ WHEN
SUM
(
CONVERT
(
- bigint,
+ bigint,
dp.wait_time
)
)/1000 > 2147483647
- THEN
+ THEN
CONVERT
(
nvarchar(30),
@@ -28809,7 +28926,7 @@ BEGIN
(
CONVERT
(
- bigint,
+ bigint,
dp.wait_time
)
)
@@ -28820,16 +28937,16 @@ BEGIN
),
14
)
- WHEN
+ WHEN
SUM
(
CONVERT
(
- bigint,
+ bigint,
dp.wait_time
)
) BETWEEN 2147483648 AND 2147483647000
- THEN
+ THEN
CONVERT
(
nvarchar(30),
@@ -28842,7 +28959,7 @@ BEGIN
(
CONVERT
(
- bigint,
+ bigint,
dp.wait_time
)
)
@@ -28924,7 +29041,7 @@ BEGIN
14
) +
N' [dd hh:mm:ss:ms] of deadlock wait time.',
- sort_order =
+ sort_order =
ROW_NUMBER()
OVER (ORDER BY cs.total_waits DESC)
FROM chopsuey AS cs
@@ -28998,19 +29115,19 @@ BEGIN
)
) +
N' ' +
- /*the more wait time you rack up the less accurate this gets,
+ /*the more wait time you rack up the less accurate this gets,
it's either that or erroring out*/
- CASE
- WHEN
+ CASE
+ WHEN
SUM
(
CONVERT
(
- bigint,
+ bigint,
wt.total_wait_time_ms
)
)/1000 > 2147483647
- THEN
+ THEN
CONVERT
(
nvarchar(30),
@@ -29023,7 +29140,7 @@ BEGIN
(
CONVERT
(
- bigint,
+ bigint,
wt.total_wait_time_ms
)
)
@@ -29034,16 +29151,16 @@ BEGIN
),
14
)
- WHEN
+ WHEN
SUM
(
CONVERT
(
- bigint,
+ bigint,
wt.total_wait_time_ms
)
) BETWEEN 2147483648 AND 2147483647000
- THEN
+ THEN
CONVERT
(
nvarchar(30),
@@ -29056,7 +29173,7 @@ BEGIN
(
CONVERT
(
- bigint,
+ bigint,
wt.total_wait_time_ms
)
)
@@ -29089,7 +29206,7 @@ BEGIN
14
) END +
N' [dd hh:mm:ss:ms] of deadlock wait time.',
- sort_order =
+ sort_order =
ROW_NUMBER()
OVER (ORDER BY SUM(CONVERT(bigint, wt.total_wait_time_ms)) DESC)
FROM wait_time AS wt
@@ -29127,7 +29244,7 @@ BEGIN
N'There have been ' +
RTRIM(COUNT_BIG(DISTINCT aj.event_date)) +
N' deadlocks from this Agent Job and Step.',
- sort_order =
+ sort_order =
ROW_NUMBER()
OVER (ORDER BY COUNT_BIG(DISTINCT aj.event_date) DESC)
FROM #agent_job AS aj
@@ -29907,23 +30024,23 @@ BEGIN
BEGIN
SET @d = CONVERT(varchar(40), GETDATE(), 109);
RAISERROR('Results to client %s', 0, 1, @d) WITH NOWAIT;
-
+
IF @Debug = 1 BEGIN SET STATISTICS XML ON; END;
-
+
EXEC sys.sp_executesql
@deadlock_result;
-
+
IF @Debug = 1
BEGIN
SET STATISTICS XML OFF;
PRINT @deadlock_result;
END;
-
+
RAISERROR('Finished at %s', 0, 1, @d) WITH NOWAIT;
SET @d = CONVERT(varchar(40), GETDATE(), 109);
RAISERROR('Getting available execution plans for deadlocks %s', 0, 1, @d) WITH NOWAIT;
-
+
SELECT DISTINCT
available_plans =
'available_plans',
@@ -29959,7 +30076,7 @@ BEGIN
CONVERT(decimal(38, 6), deqs.total_worker_time / 1000. / deqs.execution_count),
total_elapsed_time_ms =
deqs.total_elapsed_time / 1000.,
- avg_elapsed_time =
+ avg_elapsed_time_ms =
CONVERT(decimal(38, 6), deqs.total_elapsed_time / 1000. / deqs.execution_count),
executions_per_second =
ISNULL
@@ -29971,7 +30088,7 @@ BEGIN
(
SECOND,
deqs.creation_time,
- deqs.last_execution_time
+ NULLIF(deqs.last_execution_time, '1900-01-01 00:00:00.000')
),
0
),
@@ -29990,7 +30107,7 @@ BEGIN
min_used_grant_mb =
deqs.min_used_grant_kb * 8. / 1024.,
max_used_grant_mb =
- deqs.max_used_grant_kb * 8. / 1024.,
+ deqs.max_used_grant_kb * 8. / 1024.,
deqs.min_reserved_threads,
deqs.max_reserved_threads,
deqs.min_used_threads,
@@ -30000,21 +30117,21 @@ BEGIN
FROM sys.dm_exec_query_stats AS deqs
WHERE EXISTS
(
- SELECT
- 1/0
- FROM #available_plans AS ap
- WHERE ap.sql_handle = deqs.sql_handle
+ SELECT
+ 1/0
+ FROM #available_plans AS ap
+ WHERE ap.sql_handle = deqs.sql_handle
)
AND deqs.query_hash IS NOT NULL;
-
- CREATE CLUSTERED INDEX
- deqs
+
+ CREATE CLUSTERED INDEX
+ deqs
ON #dm_exec_query_stats
(
- sql_handle,
+ sql_handle,
plan_handle
);
-
+
SELECT
ap.available_plans,
ap.database_name,
@@ -30028,7 +30145,7 @@ BEGIN
ap.total_worker_time_ms,
ap.avg_worker_time_ms,
ap.total_elapsed_time_ms,
- ap.avg_elapsed_time,
+ ap.avg_elapsed_time_ms,
ap.total_logical_reads_mb,
ap.total_physical_reads_mb,
ap.total_logical_writes_mb,
@@ -30046,7 +30163,7 @@ BEGIN
ap.statement_end_offset
FROM
(
-
+
SELECT
ap.*,
c.statement_start_offset,
@@ -30057,7 +30174,7 @@ BEGIN
c.total_worker_time_ms,
c.avg_worker_time_ms,
c.total_elapsed_time_ms,
- c.avg_elapsed_time,
+ c.avg_elapsed_time_ms,
c.executions_per_second,
c.total_physical_reads_mb,
c.total_logical_writes_mb,
@@ -30096,10 +30213,10 @@ BEGIN
OPTION(RECOMPILE, LOOP JOIN, HASH JOIN);
RAISERROR('Finished at %s', 0, 1, @d) WITH NOWAIT;
-
+
SET @d = CONVERT(varchar(40), GETDATE(), 109);
RAISERROR('Returning findings %s', 0, 1, @d) WITH NOWAIT;
-
+
SELECT
df.check_id,
df.database_name,
@@ -30111,7 +30228,7 @@ BEGIN
df.check_id,
df.sort_order
OPTION(RECOMPILE);
-
+
SET @d = CONVERT(varchar(40), GETDATE(), 109);
RAISERROR('Finished at %s', 0, 1, @d) WITH NOWAIT;
END; /*done with output to client app.*/
@@ -30326,7 +30443,7 @@ BEGIN
SET STATISTICS XML OFF;
SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
- SELECT @Version = '8.17', @VersionDate = '20231010';
+ SELECT @Version = '8.18', @VersionDate = '20231222';
IF(@VersionCheckMode = 1)
BEGIN
@@ -31722,6 +31839,8 @@ DELETE FROM dbo.SqlServerVersions;
INSERT INTO dbo.SqlServerVersions
(MajorVersionNumber, MinorVersionNumber, Branch, [Url], ReleaseDate, MainstreamSupportEndDate, ExtendedSupportEndDate, MajorVersionName, MinorVersionName)
VALUES
+ (16, 4095, 'CU10', 'https://support.microsoft.com/en-us/help/5031778', '2023-11-16', '2028-01-11', '2033-01-11', 'SQL Server 2022', 'Cumulative Update 10'),
+ (16, 4085, 'CU9', 'https://support.microsoft.com/en-us/help/5030731', '2023-10-12', '2028-01-11', '2033-01-11', 'SQL Server 2022', 'Cumulative Update 9'),
(16, 4075, 'CU8', 'https://support.microsoft.com/en-us/help/5029666', '2023-09-14', '2028-01-11', '2033-01-11', 'SQL Server 2022', 'Cumulative Update 8'),
(16, 4065, 'CU7', 'https://support.microsoft.com/en-us/help/5028743', '2023-08-10', '2028-01-11', '2033-01-11', 'SQL Server 2022', 'Cumulative Update 7'),
(16, 4055, 'CU6', 'https://support.microsoft.com/en-us/help/5027505', '2023-07-13', '2028-01-11', '2033-01-11', 'SQL Server 2022', 'Cumulative Update 6'),
@@ -31732,6 +31851,8 @@ VALUES
(16, 4003, 'CU1', 'https://support.microsoft.com/en-us/help/5022375', '2023-02-16', '2028-01-11', '2033-01-11', 'SQL Server 2022', 'Cumulative Update 1'),
(16, 1050, 'RTM GDR', 'https://support.microsoft.com/kb/5021522', '2023-02-14', '2028-01-11', '2033-01-11', 'SQL Server 2022 GDR', 'RTM'),
(16, 1000, 'RTM', '', '2022-11-15', '2028-01-11', '2033-01-11', 'SQL Server 2022', 'RTM'),
+ (15, 4345, 'CU24', 'https://support.microsoft.com/kb/5031908', '2023-12-14', '2025-01-07', '2030-01-08', 'SQL Server 2019', 'Cumulative Update 24'),
+ (15, 4335, 'CU23', 'https://support.microsoft.com/kb/5030333', '2023-10-12', '2025-01-07', '2030-01-08', 'SQL Server 2019', 'Cumulative Update 23'),
(15, 4322, 'CU22', 'https://support.microsoft.com/kb/5027702', '2023-08-14', '2025-01-07', '2030-01-08', 'SQL Server 2019', 'Cumulative Update 22'),
(15, 4316, 'CU21', 'https://support.microsoft.com/kb/5025808', '2023-06-15', '2025-01-07', '2030-01-08', 'SQL Server 2019', 'Cumulative Update 21'),
(15, 4312, 'CU20', 'https://support.microsoft.com/kb/5024276', '2023-04-13', '2025-01-07', '2030-01-08', 'SQL Server 2019', 'Cumulative Update 20'),
@@ -31759,6 +31880,7 @@ VALUES
(15, 4003, 'CU1', 'https://support.microsoft.com/en-us/help/4527376', '2020-01-07', '2025-01-07', '2030-01-08', 'SQL Server 2019', 'Cumulative Update 1 '),
(15, 2070, 'GDR', 'https://support.microsoft.com/en-us/help/4517790', '2019-11-04', '2025-01-07', '2030-01-08', 'SQL Server 2019', 'RTM GDR '),
(15, 2000, 'RTM ', '', '2019-11-04', '2025-01-07', '2030-01-08', 'SQL Server 2019', 'RTM '),
+ (14, 3465, 'RTM CU31 GDR', 'https://support.microsoft.com/kb/5029376', '2023-10-12', '2022-10-11', '2027-10-12', 'SQL Server 2017', 'RTM Cumulative Update 31 GDR'),
(14, 3460, 'RTM CU31 GDR', 'https://support.microsoft.com/kb/5021126', '2023-02-14', '2022-10-11', '2027-10-12', 'SQL Server 2017', 'RTM Cumulative Update 31 GDR'),
(14, 3456, 'RTM CU31', 'https://support.microsoft.com/en-us/help/5016884', '2022-09-20', '2022-10-11', '2027-10-12', 'SQL Server 2017', 'RTM Cumulative Update 31'),
(14, 3451, 'RTM CU30', 'https://support.microsoft.com/en-us/help/5013756', '2022-07-13', '2022-10-11', '2027-10-12', 'SQL Server 2017', 'RTM Cumulative Update 30'),
@@ -32156,7 +32278,7 @@ SET NOCOUNT ON;
SET STATISTICS XML OFF;
SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
-SELECT @Version = '8.17', @VersionDate = '20231010';
+SELECT @Version = '8.18', @VersionDate = '20231222';
IF(@VersionCheckMode = 1)
BEGIN
diff --git a/Install-Core-Blitz-With-Query-Store.sql b/Install-Core-Blitz-With-Query-Store.sql
index 0075b6f1..2724cc92 100644
--- a/Install-Core-Blitz-With-Query-Store.sql
+++ b/Install-Core-Blitz-With-Query-Store.sql
@@ -38,7 +38,7 @@ AS
SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
- SELECT @Version = '8.17', @VersionDate = '20231010';
+ SELECT @Version = '8.18', @VersionDate = '20231222';
SET @OutputType = UPPER(@OutputType);
IF(@VersionCheckMode = 1)
@@ -196,14 +196,11 @@ AS
,@SkipXPFixedDrives bit = 0
,@SkipXPCMDShell bit = 0
,@SkipMaster bit = 0
- ,@SkipMSDB bit = 0
+ ,@SkipMSDB_objs bit = 0
+ ,@SkipMSDB_jobs bit = 0
,@SkipModel bit = 0
,@SkipTempDB bit = 0
,@SkipValidateLogins bit = 0
- /* Variables for check 211: */
- ,@powerScheme varchar(36)
- ,@cpu_speed_mhz int
- ,@cpu_speed_ghz decimal(18,2);
DECLARE
@db_perms table
@@ -278,38 +275,6 @@ AS
SET @SkipTrace = 1;
END; /*We need this permission to execute trace stuff, apparently*/
- IF ISNULL(@SkipXPRegRead, 0) != 1 /*If @SkipXPRegRead hasn't been set to 1 by the caller*/
- BEGIN
- BEGIN TRY
- /* Get power plan if set by group policy [Git Hub Issue #1620] */
- EXEC xp_regread @rootkey = N'HKEY_LOCAL_MACHINE',
- @key = N'SOFTWARE\Policies\Microsoft\Power\PowerSettings',
- @value_name = N'ActivePowerScheme',
- @value = @powerScheme OUTPUT,
- @no_output = N'no_output';
-
- IF @powerScheme IS NULL /* If power plan was not set by group policy, get local value [Git Hub Issue #1620]*/
- EXEC xp_regread @rootkey = N'HKEY_LOCAL_MACHINE',
- @key = N'SYSTEM\CurrentControlSet\Control\Power\User\PowerSchemes',
- @value_name = N'ActivePowerScheme',
- @value = @powerScheme OUTPUT;
-
- /* Get the cpu speed*/
- EXEC xp_regread @rootkey = N'HKEY_LOCAL_MACHINE',
- @key = N'HARDWARE\DESCRIPTION\System\CentralProcessor\0',
- @value_name = N'~MHz',
- @value = @cpu_speed_mhz OUTPUT;
-
- /* Convert the Megahertz to Gigahertz */
- SET @cpu_speed_ghz = CAST(CAST(@cpu_speed_mhz AS decimal) / 1000 AS decimal(18,2));
-
- SET @SkipXPRegRead = 0; /*We could execute xp_regread*/
- END TRY
- BEGIN CATCH
- SET @SkipXPRegRead = 1; /*We have don't have execute rights or xp_regread throws an error so skip it*/
- END CATCH;
- END; /*Need execute on xp_regread*/
-
IF NOT EXISTS
(
SELECT
@@ -379,7 +344,7 @@ AS
END;
END;
- IF ISNULL(@SkipMSDB, 0) != 1 /*If @SkipMSDB hasn't been set to 1 by the caller*/
+ IF ISNULL(@SkipMSDB_objs, 0) != 1 /*If @SkipMSDB_objs hasn't been set to 1 by the caller*/
BEGIN
IF EXISTS
(
@@ -395,16 +360,45 @@ AS
FROM msdb.sys.objects
)
BEGIN
- SET @SkipMSDB = 0; /*We have read permissions in the msdb database, and can view the objects*/
+ SET @SkipMSDB_objs = 0; /*We have read permissions in the msdb database, and can view the objects*/
END;
END TRY
BEGIN CATCH
- SET @SkipMSDB = 1; /*We have read permissions in the msdb database ... oh wait we got tricked, we can't view the objects*/
+ SET @SkipMSDB_objs = 1; /*We have read permissions in the msdb database ... oh wait we got tricked, we can't view the objects*/
END CATCH;
END;
ELSE
BEGIN
- SET @SkipMSDB = 1; /*We don't have read permissions in the msdb database*/
+ SET @SkipMSDB_objs = 1; /*We don't have read permissions in the msdb database*/
+ END;
+ END;
+
+ IF ISNULL(@SkipMSDB_jobs, 0) != 1 /*If @SkipMSDB_jobs hasn't been set to 1 by the caller*/
+ BEGIN
+ IF EXISTS
+ (
+ SELECT 1/0
+ FROM @db_perms
+ WHERE database_name = N'msdb'
+ )
+ BEGIN
+ BEGIN TRY
+ IF EXISTS
+ (
+ SELECT 1/0
+ FROM msdb.dbo.sysjobs
+ )
+ BEGIN
+ SET @SkipMSDB_jobs = 0; /*We have read permissions in the msdb database, and can view the objects*/
+ END;
+ END TRY
+ BEGIN CATCH
+ SET @SkipMSDB_jobs = 1; /*We have read permissions in the msdb database ... oh wait we got tricked, we can't view the objects*/
+ END CATCH;
+ END;
+ ELSE
+ BEGIN
+ SET @SkipMSDB_jobs = 1; /*We don't have read permissions in the msdb database*/
END;
END;
END;
@@ -576,17 +570,34 @@ AS
INSERT #SkipChecks (DatabaseName, CheckID, ServerName)
SELECT
v.*
- FROM (VALUES(NULL, 6, NULL), /*Jobs Owned By Users*/
- (NULL, 28, NULL), /*SQL Agent Job Runs at Startup*/
- (NULL, 57, NULL), /*Tables in the MSDB Database*/
+ FROM (VALUES(NULL, 28, NULL)) AS v (DatabaseName, CheckID, ServerName) /*Tables in the MSDB Database*/
+ WHERE @SkipMSDB_objs = 1;
+
+ INSERT #SkipChecks (DatabaseName, CheckID, ServerName)
+ SELECT
+ v.*
+ FROM (VALUES
+ /*sysjobs checks*/
+ (NULL, 6, NULL), /*Jobs Owned By Users*/
+ (NULL, 57, NULL), /*SQL Agent Job Runs at Startup*/
(NULL, 79, NULL), /*Shrink Database Job*/
(NULL, 94, NULL), /*Agent Jobs Without Failure Emails*/
(NULL, 123, NULL), /*Agent Jobs Starting Simultaneously*/
(NULL, 180, NULL), /*Shrink Database Step In Maintenance Plan*/
(NULL, 181, NULL), /*Repetitive Maintenance Tasks*/
- (NULL, 219, NULL) /*Alerts Without Event Descriptions*/
- ) AS v (DatabaseName, CheckID, ServerName)
- WHERE @SkipMSDB = 1;
+
+ /*sysalerts checks*/
+ (NULL, 30, NULL), /*Not All Alerts Configured*/
+ (NULL, 59, NULL), /*Alerts Configured without Follow Up*/
+ (NULL, 61, NULL), /*No Alerts for Sev 19-25*/
+ (NULL, 96, NULL), /*No Alerts for Corruption*/
+ (NULL, 98, NULL), /*Alerts Disabled*/
+ (NULL, 219, NULL), /*Alerts Without Event Descriptions*/
+
+ /*sysoperators*/
+ (NULL, 31, NULL) /*No Operators Configured/Enabled*/
+ ) AS v (DatabaseName, CheckID, ServerName)
+ WHERE @SkipMSDB_jobs = 1;
INSERT #SkipChecks (DatabaseName, CheckID, ServerName)
SELECT
@@ -630,6 +641,25 @@ AS
FROM (VALUES(NULL, 2301, NULL)) AS v (DatabaseName, CheckID, ServerName) /*sp_validatelogins*/
WHERE @SkipValidateLogins = 1
+ IF @sa = 0
+ BEGIN
+ INSERT INTO #BlitzResults
+ ( CheckID ,
+ Priority ,
+ FindingsGroup ,
+ Finding ,
+ URL ,
+ Details
+ )
+ SELECT 223 AS CheckID ,
+ 0 AS Priority ,
+ 'Informational' AS FindingsGroup ,
+ 'Some Checks Skipped' AS Finding ,
+ '' AS URL ,
+ 'User ''' + @SUSER_NAME + ''' is not part of the sysadmin role, so we skipped some checks that are not possible due to lack of permissions.' AS Details;
+ END;
+ /*End of SkipsChecks added due to permissions*/
+
IF @SkipChecksTable IS NOT NULL
AND @SkipChecksSchema IS NOT NULL
AND @SkipChecksDatabase IS NOT NULL
@@ -8674,122 +8704,147 @@ IF @ProductVersionMajor >= 10 AND NOT EXISTS ( SELECT 1
EXECUTE(@StringToExecute);
END;
- /*
- Starting with SQL Server 2014 SP2, Instant File Initialization
- is logged in the SQL Server Error Log.
- */
- IF NOT EXISTS ( SELECT 1
- FROM #SkipChecks
- WHERE DatabaseName IS NULL AND CheckID = 193 )
- AND ((@ProductVersionMajor >= 13) OR (@ProductVersionMajor = 12 AND @ProductVersionMinor >= 5000))
+ /* Performance - Instant File Initialization Not Enabled - Check 192 */
+ /* Server Info - Instant File Initialization Enabled - Check 193 */
+ IF NOT EXISTS ( SELECT 1/0
+ FROM #SkipChecks
+ WHERE DatabaseName IS NULL AND CheckID = 192 /* IFI disabled check disabled */
+ ) OR NOT EXISTS
+ ( SELECT 1/0
+ FROM #SkipChecks
+ WHERE DatabaseName IS NULL AND CheckID = 193 /* IFI enabled check disabled */
+ )
+ BEGIN
+ IF @Debug IN (1, 2) RAISERROR('Running CheckId [%d] and CheckId [%d].', 0, 1, 192, 193) WITH NOWAIT;
+
+ DECLARE @IFISetting varchar(1) = N'N'
+ ,@IFIReadDMVFailed bit = 0
+ ,@IFIAllFailed bit = 0;
+
+ /* See if we can get the instant_file_initialization_enabled column from sys.dm_server_services */
+ IF EXISTS
+ (
+ SELECT 1/0
+ FROM sys.all_columns
+ WHERE [object_id] = OBJECT_ID(N'[sys].[dm_server_services]')
+ AND [name] = N'instant_file_initialization_enabled'
+ )
BEGIN
+ /* This needs to be a "dynamic" SQL statement because if the 'instant_file_initialization_enabled' column doesn't exist the procedure might fail on a bind error */
+ SET @StringToExecute = N'SELECT @IFISetting = instant_file_initialization_enabled' + @crlf +
+ N'FROM sys.dm_server_services' + @crlf +
+ N'WHERE filename LIKE ''%sqlservr.exe%''' + @crlf +
+ N'OPTION (RECOMPILE);';
+
+ IF @Debug = 2 AND @StringToExecute IS NOT NULL PRINT @StringToExecute;
+ IF @Debug = 2 AND @StringToExecute IS NULL PRINT '@StringToExecute has gone NULL, for some reason.';
+
+ EXEC dbo.sp_executesql
+ @StringToExecute
+ ,N'@IFISetting varchar(1) OUTPUT'
+ ,@IFISetting = @IFISetting OUTPUT
- IF @Debug IN (1, 2) RAISERROR('Running CheckId [%d].', 0, 1, 193) WITH NOWAIT;
-
- -- If this is Amazon RDS, use rdsadmin.dbo.rds_read_error_log
- IF LEFT(CAST(SERVERPROPERTY('ComputerNamePhysicalNetBIOS') AS VARCHAR(8000)), 8) = 'EC2AMAZ-'
- AND LEFT(CAST(SERVERPROPERTY('MachineName') AS VARCHAR(8000)), 8) = 'EC2AMAZ-'
- AND db_id('rdsadmin') IS NOT NULL
- AND EXISTS(SELECT * FROM master.sys.all_objects WHERE name IN ('rds_startup_tasks', 'rds_help_revlogin', 'rds_hexadecimal', 'rds_failover_tracking', 'rds_database_tracking', 'rds_track_change'))
- BEGIN
- INSERT INTO #ErrorLog
- EXEC rdsadmin.dbo.rds_read_error_log 0, 1, N'Database Instant File Initialization: enabled';
- END
- ELSE
- BEGIN
- BEGIN TRY
- INSERT INTO #ErrorLog
- EXEC sys.xp_readerrorlog 0, 1, N'Database Instant File Initialization: enabled';
- END TRY
- BEGIN CATCH
- IF @Debug IN (1, 2) RAISERROR('No permissions to execute xp_readerrorlog.', 0, 1) WITH NOWAIT;
- END CATCH
- END
-
- IF EXISTS
- (
- SELECT 1/0
- FROM #ErrorLog
- WHERE LEFT([Text], 45) = N'Database Instant File Initialization: enabled'
- )
- BEGIN
- INSERT INTO #BlitzResults
- ( CheckID ,
- [Priority] ,
- FindingsGroup ,
- Finding ,
- URL ,
- Details
- )
- SELECT
- 193 AS [CheckID] ,
- 250 AS [Priority] ,
- 'Server Info' AS [FindingsGroup] ,
- 'Instant File Initialization Enabled' AS [Finding] ,
- 'https://www.brentozar.com/go/instant' AS [URL] ,
- 'The service account has the Perform Volume Maintenance Tasks permission.';
- END;
- else -- if version of sql server has instant_file_initialization_enabled column in dm_server_services, check that too
- -- in the event the error log has been cycled and the startup messages are not in the current error log
- begin
- 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_server_services'
- AND c.name = 'instant_file_initialization_enabled' )
- begin
- SET @StringToExecute = N'
- INSERT INTO #BlitzResults
- ( CheckID ,
- [Priority] ,
- FindingsGroup ,
- Finding ,
- URL ,
- Details
- )
- SELECT
- 193 AS [CheckID] ,
- 250 AS [Priority] ,
- ''Server Info'' AS [FindingsGroup] ,
- ''Instant File Initialization Enabled'' AS [Finding] ,
- ''https://www.brentozar.com/go/instant'' AS [URL] ,
- ''The service account has the Perform Volume Maintenance Tasks permission.''
- where exists (select 1 FROM sys.dm_server_services
- WHERE instant_file_initialization_enabled = ''Y''
- AND filename LIKE ''%sqlservr.exe%'')
- OPTION (RECOMPILE);';
- EXEC(@StringToExecute);
- end;
- end;
- END;
+ SET @IFIReadDMVFailed = 0;
+ END
+ ELSE
+ /* We couldn't get the instant_file_initialization_enabled column from sys.dm_server_services, fall back to read error log */
+ BEGIN
+ SET @IFIReadDMVFailed = 1;
+ /* If this is Amazon RDS, we'll use the rdsadmin.dbo.rds_read_error_log */
+ IF LEFT(CAST(SERVERPROPERTY('ComputerNamePhysicalNetBIOS') AS VARCHAR(8000)), 8) = 'EC2AMAZ-'
+ AND LEFT(CAST(SERVERPROPERTY('MachineName') AS VARCHAR(8000)), 8) = 'EC2AMAZ-'
+ AND db_id('rdsadmin') IS NOT NULL
+ AND EXISTS ( SELECT 1/0
+ FROM master.sys.all_objects
+ WHERE name IN ('rds_startup_tasks', 'rds_help_revlogin', 'rds_hexadecimal', 'rds_failover_tracking', 'rds_database_tracking', 'rds_track_change')
+ )
+ BEGIN
+ /* Amazon RDS detected, read rdsadmin.dbo.rds_read_error_log */
+ INSERT INTO #ErrorLog
+ EXEC rdsadmin.dbo.rds_read_error_log 0, 1, N'Database Instant File Initialization: enabled';
+ END
+ ELSE
+ BEGIN
+ /* Try to read the error log, this might fail due to permissions */
+ BEGIN TRY
+ INSERT INTO #ErrorLog
+ EXEC sys.xp_readerrorlog 0, 1, N'Database Instant File Initialization: enabled';
+ END TRY
+ BEGIN CATCH
+ IF @Debug IN (1, 2) RAISERROR('No permissions to execute xp_readerrorlog.', 0, 1) WITH NOWAIT;
+ SET @IFIAllFailed = 1;
+ END CATCH
+ END;
+ END;
+
+ IF @IFIAllFailed = 0
+ BEGIN
+ IF @IFIReadDMVFailed = 1
+ /* We couldn't read the DMV so set the @IFISetting variable using the error log */
+ BEGIN
+ IF EXISTS ( SELECT 1/0
+ FROM #ErrorLog
+ WHERE LEFT([Text], 45) = N'Database Instant File Initialization: enabled'
+ )
+ BEGIN
+ SET @IFISetting = 'Y';
+ END
+ ELSE
+ BEGIN
+ SET @IFISetting = 'N';
+ END;
+ END;
+
+ IF NOT EXISTS ( SELECT 1/0
+ FROM #SkipChecks
+ WHERE DatabaseName IS NULL AND CheckID = 192 /* IFI disabled check disabled */
+ ) AND @IFISetting = 'N'
+ BEGIN
+ INSERT INTO #BlitzResults
+ (
+ CheckID ,
+ [Priority] ,
+ FindingsGroup ,
+ Finding ,
+ URL ,
+ Details
+ )
+ SELECT
+ 192 AS [CheckID] ,
+ 50 AS [Priority] ,
+ 'Performance' AS [FindingsGroup] ,
+ 'Instant File Initialization Not Enabled' AS [Finding] ,
+ 'https://www.brentozar.com/go/instant' AS [URL] ,
+ 'Consider enabling IFI for faster restores and data file growths.' AS [Details]
+ END;
+
+ IF NOT EXISTS ( SELECT 1/0
+ FROM #SkipChecks
+ WHERE DatabaseName IS NULL AND CheckID = 193 /* IFI enabled check disabled */
+ ) AND @IFISetting = 'Y'
+ BEGIN
+ INSERT INTO #BlitzResults
+ (
+ CheckID ,
+ [Priority] ,
+ FindingsGroup ,
+ Finding ,
+ URL ,
+ Details
+ )
+ SELECT
+ 193 AS [CheckID] ,
+ 250 AS [Priority] ,
+ 'Server Info' AS [FindingsGroup] ,
+ 'Instant File Initialization Enabled' AS [Finding] ,
+ 'https://www.brentozar.com/go/instant' AS [URL] ,
+ 'The service account has the Perform Volume Maintenance Tasks permission.' AS [Details]
+ END;
+ END;
+ END;
- /* Server Info - Instant File Initialization Not Enabled - Check 192 - SQL Server 2016 SP1 and newer */
- IF NOT EXISTS ( SELECT 1
- FROM #SkipChecks
- WHERE DatabaseName IS NULL AND CheckID = 192 )
- AND EXISTS ( SELECT *
- FROM sys.all_objects o
- INNER JOIN sys.all_columns c ON o.object_id = c.object_id
- WHERE o.name = 'dm_server_services'
- AND c.name = 'instant_file_initialization_enabled' )
- BEGIN
-
- IF @Debug IN (1, 2) RAISERROR('Running CheckId [%d].', 0, 1, 192) WITH NOWAIT;
-
- SET @StringToExecute = 'INSERT INTO #BlitzResults (CheckID, Priority, FindingsGroup, Finding, URL, Details)
- SELECT 192 AS CheckID ,
- 50 AS Priority ,
- ''Server Info'' AS FindingsGroup ,
- ''Instant File Initialization Not Enabled'' AS Finding ,
- ''https://www.brentozar.com/go/instant'' AS URL ,
- ''Consider enabling IFI for faster restores and data file growths.''
- FROM sys.dm_server_services WHERE instant_file_initialization_enabled <> ''Y'' AND filename LIKE ''%sqlservr.exe%'' OPTION (RECOMPILE);';
-
- IF @Debug = 2 AND @StringToExecute IS NOT NULL PRINT @StringToExecute;
- IF @Debug = 2 AND @StringToExecute IS NULL PRINT '@StringToExecute has gone NULL, for some reason.';
-
- EXECUTE(@StringToExecute);
- END;
+ /* End of checkId 192 */
+ /* End of checkId 193 */
IF NOT EXISTS ( SELECT 1
FROM #SkipChecks
@@ -9167,7 +9222,39 @@ IF @ProductVersionMajor >= 10 AND NOT EXISTS ( SELECT 1
WHERE DatabaseName IS NULL AND CheckID = 211 )
BEGIN
+ /* Variables for check 211: */
+ DECLARE
+ @powerScheme varchar(36)
+ ,@cpu_speed_mhz int
+ ,@cpu_speed_ghz decimal(18,2)
+ ,@ExecResult int;
+
IF @Debug IN (1, 2) RAISERROR('Running CheckId [%d].', 0, 1, 211) WITH NOWAIT;
+ IF @sa = 0 RAISERROR('The errors: ''xp_regread() returned error 5, ''Access is denied.'''' can be safely ignored', 0, 1) WITH NOWAIT;
+
+ /* Get power plan if set by group policy [Git Hub Issue #1620] */
+ EXEC xp_regread @rootkey = N'HKEY_LOCAL_MACHINE',
+ @key = N'SOFTWARE\Policies\Microsoft\Power\PowerSettings',
+ @value_name = N'ActivePowerScheme',
+ @value = @powerScheme OUTPUT,
+ @no_output = N'no_output';
+
+ IF @powerScheme IS NULL /* If power plan was not set by group policy, get local value [Git Hub Issue #1620]*/
+ EXEC xp_regread @rootkey = N'HKEY_LOCAL_MACHINE',
+ @key = N'SYSTEM\CurrentControlSet\Control\Power\User\PowerSchemes',
+ @value_name = N'ActivePowerScheme',
+ @value = @powerScheme OUTPUT;
+
+ /* Get the cpu speed*/
+ EXEC @ExecResult = xp_regread @rootkey = N'HKEY_LOCAL_MACHINE',
+ @key = N'HARDWARE\DESCRIPTION\System\CentralProcessor\0',
+ @value_name = N'~MHz',
+ @value = @cpu_speed_mhz OUTPUT;
+
+ /* Convert the Megahertz to Gigahertz */
+ IF @ExecResult != 0 RAISERROR('We couldn''t retrieve the CPU speed, you will see Unknown in the results', 0, 1)
+
+ SET @cpu_speed_ghz = CAST(CAST(@cpu_speed_mhz AS decimal) / 1000 AS decimal(18,2));
INSERT INTO #BlitzResults
( CheckID ,
@@ -9183,7 +9270,7 @@ IF @ProductVersionMajor >= 10 AND NOT EXISTS ( SELECT 1
'Power Plan' AS Finding,
'https://www.brentozar.com/blitz/power-mode/' AS URL,
'Your server has '
- + CAST(@cpu_speed_ghz as VARCHAR(4))
+ + ISNULL(CAST(@cpu_speed_ghz as VARCHAR(8)), 'Unknown ')
+ 'GHz CPUs, and is in '
+ CASE @powerScheme
WHEN 'a1841308-3541-4fab-bc81-f71556f20b4a'
@@ -9839,20 +9926,22 @@ IF @ProductVersionMajor >= 10 AND NOT EXISTS ( SELECT 1
FROM #BlitzResults
WHERE Priority > 0 AND Priority < 255 AND FindingsGroup IS NOT NULL AND Finding IS NOT NULL
AND FindingsGroup <> 'Security' /* Specifically excluding security checks for public exports */)
- SELECT
- CASE
- WHEN r.Priority <> COALESCE(rPrior.Priority, 0) OR r.FindingsGroup <> rPrior.FindingsGroup THEN @crlf + N'**Priority ' + CAST(COALESCE(r.Priority,N'') AS NVARCHAR(5)) + N': ' + COALESCE(r.FindingsGroup,N'') + N'**:' + @crlf + @crlf
- ELSE N''
- END
- + CASE WHEN r.Finding <> COALESCE(rPrior.Finding,N'') AND r.Finding <> COALESCE(rNext.Finding,N'') THEN N'- ' + COALESCE(r.Finding,N'') + N' ' + COALESCE(r.DatabaseName, N'') + N' - ' + COALESCE(r.Details,N'') + @crlf
- WHEN r.Finding <> COALESCE(rPrior.Finding,N'') AND r.Finding = rNext.Finding AND r.Details = rNext.Details THEN N'- ' + COALESCE(r.Finding,N'') + N' - ' + COALESCE(r.Details,N'') + @crlf + @crlf + N' * ' + COALESCE(r.DatabaseName, N'') + @crlf
- WHEN r.Finding <> COALESCE(rPrior.Finding,N'') AND r.Finding = rNext.Finding THEN N'- ' + COALESCE(r.Finding,N'') + @crlf + CASE WHEN r.DatabaseName IS NULL THEN N'' ELSE N' * ' + COALESCE(r.DatabaseName,N'') END + CASE WHEN r.Details <> rPrior.Details THEN N' - ' + COALESCE(r.Details,N'') + @crlf ELSE '' END
- ELSE CASE WHEN r.DatabaseName IS NULL THEN N'' ELSE N' * ' + COALESCE(r.DatabaseName,N'') END + CASE WHEN r.Details <> rPrior.Details THEN N' - ' + COALESCE(r.Details,N'') + @crlf ELSE N'' + @crlf END
- END + @crlf
- FROM Results r
- LEFT OUTER JOIN Results rPrior ON r.rownum = rPrior.rownum + 1
- LEFT OUTER JOIN Results rNext ON r.rownum = rNext.rownum - 1
- ORDER BY r.rownum FOR XML PATH(N'');
+ SELECT
+ Markdown = CONVERT(XML, STUFF((SELECT
+ CASE
+ WHEN r.Priority <> COALESCE(rPrior.Priority, 0) OR r.FindingsGroup <> rPrior.FindingsGroup THEN @crlf + N'**Priority ' + CAST(COALESCE(r.Priority,N'') AS NVARCHAR(5)) + N': ' + COALESCE(r.FindingsGroup,N'') + N'**:' + @crlf + @crlf
+ ELSE N''
+ END
+ + CASE WHEN r.Finding <> COALESCE(rPrior.Finding,N'') AND r.Finding <> COALESCE(rNext.Finding,N'') THEN N'- ' + COALESCE(r.Finding,N'') + N' ' + COALESCE(r.DatabaseName, N'') + N' - ' + COALESCE(r.Details,N'') + @crlf
+ WHEN r.Finding <> COALESCE(rPrior.Finding,N'') AND r.Finding = rNext.Finding AND r.Details = rNext.Details THEN N'- ' + COALESCE(r.Finding,N'') + N' - ' + COALESCE(r.Details,N'') + @crlf + @crlf + N' * ' + COALESCE(r.DatabaseName, N'') + @crlf
+ WHEN r.Finding <> COALESCE(rPrior.Finding,N'') AND r.Finding = rNext.Finding THEN N'- ' + COALESCE(r.Finding,N'') + @crlf + @crlf + CASE WHEN r.DatabaseName IS NULL THEN N'' ELSE N' * ' + COALESCE(r.DatabaseName,N'') END + CASE WHEN r.Details <> rPrior.Details THEN N' - ' + COALESCE(r.Details,N'') + @crlf ELSE '' END
+ ELSE CASE WHEN r.DatabaseName IS NULL THEN N'' ELSE N' * ' + COALESCE(r.DatabaseName,N'') END + CASE WHEN r.Details <> rPrior.Details THEN N' - ' + COALESCE(r.Details,N'') + @crlf ELSE N'' + @crlf END
+ END + @crlf
+ FROM Results r
+ LEFT OUTER JOIN Results rPrior ON r.rownum = rPrior.rownum + 1
+ LEFT OUTER JOIN Results rNext ON r.rownum = rNext.rownum - 1
+ ORDER BY r.rownum FOR XML PATH(N''), ROOT('Markdown'), TYPE).value('/Markdown[1]','VARCHAR(MAX)'), 1, 2, '')
+ + '');
END;
ELSE IF @OutputType = 'XML'
BEGIN
@@ -10016,7 +10105,7 @@ AS
SET NOCOUNT ON;
SET STATISTICS XML OFF;
-SELECT @Version = '8.17', @VersionDate = '20231010';
+SELECT @Version = '8.18', @VersionDate = '20231222';
IF(@VersionCheckMode = 1)
BEGIN
@@ -10894,7 +10983,7 @@ AS
SET STATISTICS XML OFF;
SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
- SELECT @Version = '8.17', @VersionDate = '20231010';
+ SELECT @Version = '8.18', @VersionDate = '20231222';
IF(@VersionCheckMode = 1)
BEGIN
@@ -12676,7 +12765,7 @@ SET NOCOUNT ON;
SET STATISTICS XML OFF;
SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
-SELECT @Version = '8.17', @VersionDate = '20231010';
+SELECT @Version = '8.18', @VersionDate = '20231222';
SET @OutputType = UPPER(@OutputType);
IF(@VersionCheckMode = 1)
@@ -19733,16 +19822,16 @@ END ';
IF @Debug = 1
BEGIN
- PRINT SUBSTRING(@StringToExecute, 0, 4000);
- PRINT SUBSTRING(@StringToExecute, 4000, 8000);
- PRINT SUBSTRING(@StringToExecute, 8000, 12000);
- PRINT SUBSTRING(@StringToExecute, 12000, 16000);
- PRINT SUBSTRING(@StringToExecute, 16000, 20000);
- PRINT SUBSTRING(@StringToExecute, 20000, 24000);
- PRINT SUBSTRING(@StringToExecute, 24000, 28000);
- PRINT SUBSTRING(@StringToExecute, 28000, 32000);
- PRINT SUBSTRING(@StringToExecute, 32000, 36000);
- PRINT SUBSTRING(@StringToExecute, 36000, 40000);
+ PRINT SUBSTRING(@StringToExecute, 1, 4000);
+ PRINT SUBSTRING(@StringToExecute, 4001, 4000);
+ PRINT SUBSTRING(@StringToExecute, 8001, 4000);
+ PRINT SUBSTRING(@StringToExecute, 12001, 4000);
+ PRINT SUBSTRING(@StringToExecute, 16001, 4000);
+ PRINT SUBSTRING(@StringToExecute, 20001, 4000);
+ PRINT SUBSTRING(@StringToExecute, 24001, 4000);
+ PRINT SUBSTRING(@StringToExecute, 28001, 4000);
+ PRINT SUBSTRING(@StringToExecute, 32001, 4000);
+ PRINT SUBSTRING(@StringToExecute, 36001, 4000);
END;
EXEC sp_executesql @StringToExecute, N'@Top INT, @min_duration INT, @min_back INT, @CheckDateOverride DATETIMEOFFSET, @MinimumExecutionCount INT', @Top, @DurationFilter_i, @MinutesBack, @CheckDateOverride, @MinimumExecutionCount;
@@ -20035,7 +20124,7 @@ SET NOCOUNT ON;
SET STATISTICS XML OFF;
SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
-SELECT @Version = '8.17', @VersionDate = '20231010';
+SELECT @Version = '8.18', @VersionDate = '20231222';
SET @OutputType = UPPER(@OutputType);
IF(@VersionCheckMode = 1)
@@ -21201,16 +21290,16 @@ BEGIN TRY
RAISERROR (N'Inserting data into #IndexColumns for clustered indexes and heaps',0,1) WITH NOWAIT;
IF @Debug = 1
BEGIN
- PRINT SUBSTRING(@dsql, 0, 4000);
- PRINT SUBSTRING(@dsql, 4000, 8000);
- PRINT SUBSTRING(@dsql, 8000, 12000);
- PRINT SUBSTRING(@dsql, 12000, 16000);
- PRINT SUBSTRING(@dsql, 16000, 20000);
- PRINT SUBSTRING(@dsql, 20000, 24000);
- PRINT SUBSTRING(@dsql, 24000, 28000);
- PRINT SUBSTRING(@dsql, 28000, 32000);
- PRINT SUBSTRING(@dsql, 32000, 36000);
- PRINT SUBSTRING(@dsql, 36000, 40000);
+ PRINT SUBSTRING(@dsql, 1, 4000);
+ PRINT SUBSTRING(@dsql, 4001, 4000);
+ PRINT SUBSTRING(@dsql, 8001, 4000);
+ PRINT SUBSTRING(@dsql, 12001, 4000);
+ PRINT SUBSTRING(@dsql, 16001, 4000);
+ PRINT SUBSTRING(@dsql, 20001, 4000);
+ PRINT SUBSTRING(@dsql, 24001, 4000);
+ PRINT SUBSTRING(@dsql, 28001, 4000);
+ PRINT SUBSTRING(@dsql, 32001, 4000);
+ PRINT SUBSTRING(@dsql, 36001, 4000);
END;
BEGIN TRY
INSERT #IndexColumns ( database_id, [schema_name], [object_id], index_id, key_ordinal, is_included_column, is_descending_key, partition_ordinal,
@@ -22578,6 +22667,7 @@ SELECT
FROM #IndexSanity;
RAISERROR (N'Populate #PartitionCompressionInfo.',0,1) WITH NOWAIT;
+IF OBJECT_ID('tempdb..#maps') IS NOT NULL DROP TABLE #maps;
WITH maps
AS
(
@@ -22592,6 +22682,7 @@ SELECT *
INTO #maps
FROM maps;
+IF OBJECT_ID('tempdb..#grps') IS NOT NULL DROP TABLE #grps;
WITH grps
AS
(
@@ -26217,10 +26308,11 @@ WITH RECOMPILE
AS
BEGIN
SET STATISTICS XML OFF;
- SET NOCOUNT, XACT_ABORT ON;
+ SET NOCOUNT ON;
+ SET XACT_ABORT OFF;
SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
- SELECT @Version = '8.17', @VersionDate = '20231010';
+ SELECT @Version = '8.18', @VersionDate = '20231222';
IF @VersionCheckMode = 1
BEGIN
@@ -26344,6 +26436,20 @@ BEGIN
THEN 1
ELSE 0
END,
+ @MI bit =
+ CASE
+ WHEN
+ (
+ SELECT
+ CONVERT
+ (
+ integer,
+ SERVERPROPERTY('EngineEdition')
+ )
+ ) = 8
+ THEN 1
+ ELSE 0
+ END,
@RDS bit =
CASE
WHEN LEFT(CAST(SERVERPROPERTY('ComputerNamePhysicalNetBIOS') AS varchar(8000)), 8) <> 'EC2AMAZ-'
@@ -26482,6 +26588,17 @@ BEGIN
@StartDateUTC = @StartDate,
@EndDateUTC = @EndDate;
+ IF
+ (
+ @MI = 1
+ AND @EventSessionName = N'system_health'
+ AND @TargetSessionType IS NULL
+ )
+ BEGIN
+ SET
+ @TargetSessionType = N'ring_buffer';
+ END;
+
IF @Azure = 0
BEGIN
IF NOT EXISTS
@@ -26499,7 +26616,7 @@ BEGIN
RETURN;
END;
END;
-
+
IF @Azure = 1
BEGIN
IF NOT EXISTS
@@ -28029,7 +28146,7 @@ BEGIN
COUNT_BIG(DISTINCT dp.event_date)
) +
N' deadlocks.',
- sort_order =
+ sort_order =
ROW_NUMBER()
OVER (ORDER BY COUNT_BIG(DISTINCT dp.event_date) DESC)
FROM #deadlock_process AS dp
@@ -28069,7 +28186,7 @@ BEGIN
SELECT
1/0
FROM sys.databases AS d
- WHERE d.name = dow.database_name
+ WHERE d.name COLLATE DATABASE_DEFAULT = dow.database_name COLLATE DATABASE_DEFAULT
AND d.is_read_committed_snapshot_on = 1
)
THEN N'You already enabled RCSI, but...'
@@ -28084,7 +28201,7 @@ BEGIN
COUNT_BIG(DISTINCT dow.event_date)
) +
N' deadlock(s) between read queries and modification queries.',
- sort_order =
+ sort_order =
ROW_NUMBER()
OVER (ORDER BY COUNT_BIG(DISTINCT dow.event_date) DESC)
FROM #deadlock_owner_waiter AS dow
@@ -28146,7 +28263,7 @@ BEGIN
COUNT_BIG(DISTINCT dow.event_date)
) +
N' deadlock(s).',
- sort_order =
+ sort_order =
ROW_NUMBER()
OVER (ORDER BY COUNT_BIG(DISTINCT dow.event_date) DESC)
FROM #deadlock_owner_waiter AS dow
@@ -28189,7 +28306,7 @@ BEGIN
COUNT_BIG(DISTINCT dow.event_date)
) +
N' deadlock(s).',
- sort_order =
+ sort_order =
ROW_NUMBER()
OVER (ORDER BY COUNT_BIG(DISTINCT dow.event_date) DESC)
FROM #deadlock_owner_waiter AS dow
@@ -28238,7 +28355,7 @@ BEGIN
COUNT_BIG(DISTINCT dow.event_date)
) +
N' deadlock(s).',
- sort_order =
+ sort_order =
ROW_NUMBER()
OVER (ORDER BY COUNT_BIG(DISTINCT dow.event_date) DESC)
FROM #deadlock_owner_waiter AS dow
@@ -28287,7 +28404,7 @@ BEGIN
COUNT_BIG(DISTINCT dp.event_date)
) +
N' instances of Serializable deadlocks.',
- sort_order =
+ sort_order =
ROW_NUMBER()
OVER (ORDER BY COUNT_BIG(DISTINCT dp.event_date) DESC)
FROM #deadlock_process AS dp
@@ -28330,7 +28447,7 @@ BEGIN
COUNT_BIG(DISTINCT dp.event_date)
) +
N' instances of Repeatable Read deadlocks.',
- sort_order =
+ sort_order =
ROW_NUMBER()
OVER (ORDER BY COUNT_BIG(DISTINCT dp.event_date) DESC)
FROM #deadlock_process AS dp
@@ -28392,7 +28509,7 @@ BEGIN
N'UNKNOWN'
) +
N'.',
- sort_order =
+ sort_order =
ROW_NUMBER()
OVER (ORDER BY COUNT_BIG(DISTINCT dp.event_date) DESC)
FROM #deadlock_process AS dp
@@ -28504,7 +28621,7 @@ BEGIN
1,
N''
) + N' locks.',
- sort_order =
+ sort_order =
ROW_NUMBER()
OVER (ORDER BY CONVERT(bigint, lt.lock_count) DESC)
FROM lock_types AS lt
@@ -28683,7 +28800,7 @@ BEGIN
COUNT_BIG(DISTINCT ds.id)
) +
N' deadlocks.',
- sort_order =
+ sort_order =
ROW_NUMBER()
OVER (ORDER BY COUNT_BIG(DISTINCT ds.id) DESC)
FROM #deadlock_stack AS ds
@@ -28784,19 +28901,19 @@ BEGIN
)
),
wait_time_hms =
- /*the more wait time you rack up the less accurate this gets,
+ /*the more wait time you rack up the less accurate this gets,
it's either that or erroring out*/
- CASE
- WHEN
+ CASE
+ WHEN
SUM
(
CONVERT
(
- bigint,
+ bigint,
dp.wait_time
)
)/1000 > 2147483647
- THEN
+ THEN
CONVERT
(
nvarchar(30),
@@ -28809,7 +28926,7 @@ BEGIN
(
CONVERT
(
- bigint,
+ bigint,
dp.wait_time
)
)
@@ -28820,16 +28937,16 @@ BEGIN
),
14
)
- WHEN
+ WHEN
SUM
(
CONVERT
(
- bigint,
+ bigint,
dp.wait_time
)
) BETWEEN 2147483648 AND 2147483647000
- THEN
+ THEN
CONVERT
(
nvarchar(30),
@@ -28842,7 +28959,7 @@ BEGIN
(
CONVERT
(
- bigint,
+ bigint,
dp.wait_time
)
)
@@ -28924,7 +29041,7 @@ BEGIN
14
) +
N' [dd hh:mm:ss:ms] of deadlock wait time.',
- sort_order =
+ sort_order =
ROW_NUMBER()
OVER (ORDER BY cs.total_waits DESC)
FROM chopsuey AS cs
@@ -28998,19 +29115,19 @@ BEGIN
)
) +
N' ' +
- /*the more wait time you rack up the less accurate this gets,
+ /*the more wait time you rack up the less accurate this gets,
it's either that or erroring out*/
- CASE
- WHEN
+ CASE
+ WHEN
SUM
(
CONVERT
(
- bigint,
+ bigint,
wt.total_wait_time_ms
)
)/1000 > 2147483647
- THEN
+ THEN
CONVERT
(
nvarchar(30),
@@ -29023,7 +29140,7 @@ BEGIN
(
CONVERT
(
- bigint,
+ bigint,
wt.total_wait_time_ms
)
)
@@ -29034,16 +29151,16 @@ BEGIN
),
14
)
- WHEN
+ WHEN
SUM
(
CONVERT
(
- bigint,
+ bigint,
wt.total_wait_time_ms
)
) BETWEEN 2147483648 AND 2147483647000
- THEN
+ THEN
CONVERT
(
nvarchar(30),
@@ -29056,7 +29173,7 @@ BEGIN
(
CONVERT
(
- bigint,
+ bigint,
wt.total_wait_time_ms
)
)
@@ -29089,7 +29206,7 @@ BEGIN
14
) END +
N' [dd hh:mm:ss:ms] of deadlock wait time.',
- sort_order =
+ sort_order =
ROW_NUMBER()
OVER (ORDER BY SUM(CONVERT(bigint, wt.total_wait_time_ms)) DESC)
FROM wait_time AS wt
@@ -29127,7 +29244,7 @@ BEGIN
N'There have been ' +
RTRIM(COUNT_BIG(DISTINCT aj.event_date)) +
N' deadlocks from this Agent Job and Step.',
- sort_order =
+ sort_order =
ROW_NUMBER()
OVER (ORDER BY COUNT_BIG(DISTINCT aj.event_date) DESC)
FROM #agent_job AS aj
@@ -29907,23 +30024,23 @@ BEGIN
BEGIN
SET @d = CONVERT(varchar(40), GETDATE(), 109);
RAISERROR('Results to client %s', 0, 1, @d) WITH NOWAIT;
-
+
IF @Debug = 1 BEGIN SET STATISTICS XML ON; END;
-
+
EXEC sys.sp_executesql
@deadlock_result;
-
+
IF @Debug = 1
BEGIN
SET STATISTICS XML OFF;
PRINT @deadlock_result;
END;
-
+
RAISERROR('Finished at %s', 0, 1, @d) WITH NOWAIT;
SET @d = CONVERT(varchar(40), GETDATE(), 109);
RAISERROR('Getting available execution plans for deadlocks %s', 0, 1, @d) WITH NOWAIT;
-
+
SELECT DISTINCT
available_plans =
'available_plans',
@@ -29959,7 +30076,7 @@ BEGIN
CONVERT(decimal(38, 6), deqs.total_worker_time / 1000. / deqs.execution_count),
total_elapsed_time_ms =
deqs.total_elapsed_time / 1000.,
- avg_elapsed_time =
+ avg_elapsed_time_ms =
CONVERT(decimal(38, 6), deqs.total_elapsed_time / 1000. / deqs.execution_count),
executions_per_second =
ISNULL
@@ -29971,7 +30088,7 @@ BEGIN
(
SECOND,
deqs.creation_time,
- deqs.last_execution_time
+ NULLIF(deqs.last_execution_time, '1900-01-01 00:00:00.000')
),
0
),
@@ -29990,7 +30107,7 @@ BEGIN
min_used_grant_mb =
deqs.min_used_grant_kb * 8. / 1024.,
max_used_grant_mb =
- deqs.max_used_grant_kb * 8. / 1024.,
+ deqs.max_used_grant_kb * 8. / 1024.,
deqs.min_reserved_threads,
deqs.max_reserved_threads,
deqs.min_used_threads,
@@ -30000,21 +30117,21 @@ BEGIN
FROM sys.dm_exec_query_stats AS deqs
WHERE EXISTS
(
- SELECT
- 1/0
- FROM #available_plans AS ap
- WHERE ap.sql_handle = deqs.sql_handle
+ SELECT
+ 1/0
+ FROM #available_plans AS ap
+ WHERE ap.sql_handle = deqs.sql_handle
)
AND deqs.query_hash IS NOT NULL;
-
- CREATE CLUSTERED INDEX
- deqs
+
+ CREATE CLUSTERED INDEX
+ deqs
ON #dm_exec_query_stats
(
- sql_handle,
+ sql_handle,
plan_handle
);
-
+
SELECT
ap.available_plans,
ap.database_name,
@@ -30028,7 +30145,7 @@ BEGIN
ap.total_worker_time_ms,
ap.avg_worker_time_ms,
ap.total_elapsed_time_ms,
- ap.avg_elapsed_time,
+ ap.avg_elapsed_time_ms,
ap.total_logical_reads_mb,
ap.total_physical_reads_mb,
ap.total_logical_writes_mb,
@@ -30046,7 +30163,7 @@ BEGIN
ap.statement_end_offset
FROM
(
-
+
SELECT
ap.*,
c.statement_start_offset,
@@ -30057,7 +30174,7 @@ BEGIN
c.total_worker_time_ms,
c.avg_worker_time_ms,
c.total_elapsed_time_ms,
- c.avg_elapsed_time,
+ c.avg_elapsed_time_ms,
c.executions_per_second,
c.total_physical_reads_mb,
c.total_logical_writes_mb,
@@ -30096,10 +30213,10 @@ BEGIN
OPTION(RECOMPILE, LOOP JOIN, HASH JOIN);
RAISERROR('Finished at %s', 0, 1, @d) WITH NOWAIT;
-
+
SET @d = CONVERT(varchar(40), GETDATE(), 109);
RAISERROR('Returning findings %s', 0, 1, @d) WITH NOWAIT;
-
+
SELECT
df.check_id,
df.database_name,
@@ -30111,7 +30228,7 @@ BEGIN
df.check_id,
df.sort_order
OPTION(RECOMPILE);
-
+
SET @d = CONVERT(varchar(40), GETDATE(), 109);
RAISERROR('Finished at %s', 0, 1, @d) WITH NOWAIT;
END; /*done with output to client app.*/
@@ -30350,7 +30467,7 @@ SET NOCOUNT ON;
SET STATISTICS XML OFF;
SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
-SELECT @Version = '8.17', @VersionDate = '20231010';
+SELECT @Version = '8.18', @VersionDate = '20231222';
IF(@VersionCheckMode = 1)
BEGIN
RETURN;
@@ -30411,8 +30528,6 @@ IF (SELECT CONVERT(NVARCHAR(128), SERVERPROPERTY ('EDITION'))) <> 'SQL Azure'
IF @Help = 1
BEGIN
-
- SELECT N'You have requested assistance. It will arrive as soon as humanly possible.' AS [Take four red capsules, help is on the way];
PRINT N'
sp_BlitzQueryStore from http://FirstResponderKit.org
@@ -30456,6 +30571,257 @@ IF @Help = 1
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
';
+ /*Parameter info*/
+ SELECT N'@Help' AS [Parameter Name] ,
+ N'BIT' AS [Data Type] ,
+ N'0' AS [Default Value],
+ N'Displays this help message.' AS [Parameter Description]
+ UNION ALL
+ SELECT N'@DatabaseName',
+ N'NVARCHAR(128)',
+ N'NULL',
+ N'The name of the database you want to check the query store for.'
+ UNION ALL
+ SELECT N'@Top',
+ N'INT',
+ N'3',
+ N'The number of records to retrieve and analyze from the query store. The following system views are used: query_store_query, query_context_settings, query_store_wait_stats, query_store_runtime_stats,query_store_plan.'
+
+ UNION ALL
+ SELECT N'@StartDate',
+ N'DATETIME2(7)',
+ N'NULL',
+ N'Get query store info starting from this date. When not specified, sp_BlitzQueryStore gets info from the last 7 days'
+ UNION ALL
+ SELECT N'@EndDate',
+ N'DATETIME2(7)',
+ N'NULL',
+ N'Get query store info until this date. When not specified, sp_BlitzQueryStore gets info from the last 7 days'
+ UNION ALL
+ SELECT N'@MinimumExecutionCount',
+ N'INT',
+ N'NULL',
+ N'When a value is specified, sp_BlitzQueryStore gets info for queries where count_executions >= @MinimumExecutionCount'
+ UNION ALL
+ SELECT N'@DurationFilter',
+ N'DECIMAL(38,4)',
+ N'NULL',
+ N'Time unit - seconds. When a value is specified, sp_BlitzQueryStore gets info for queries where the average duration >= @DurationFilter'
+ UNION ALL
+ SELECT N'@StoredProcName',
+ N'NVARCHAR(128)',
+ N'NULL',
+ N'Get information for this specific stored procedure.'
+ UNION ALL
+ SELECT N'@Failed',
+ N'BIT',
+ N'0',
+ N'When set to 1, only information about failed queries is returned.'
+ UNION ALL
+ SELECT N'@PlanIdFilter',
+ N'INT',
+ N'NULL',
+ N'The ID of the plan you want to check for.'
+ UNION ALL
+ SELECT N'@QueryIdFilter',
+ N'INT',
+ N'NULL',
+ N'The ID of the query you want to check for.'
+ UNION ALL
+ SELECT N'@ExportToExcel',
+ N'BIT',
+ N'0',
+ N'When set to 1, prepares 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'@HideSummary',
+ N'BIT',
+ N'0',
+ N'When set to 1, hides the findings summary result set.'
+ UNION ALL
+ SELECT N'@SkipXML',
+ N'BIT',
+ N'0',
+ N'When set to 1, missing_indexes, implicit_conversion_info, cached_execution_parameters, are not returned. Does not affect query_plan_xml'
+ UNION ALL
+ SELECT N'@Debug',
+ N'BIT',
+ N'0',
+ N'Setting this to 1 will print dynamic SQL and select data from all tables used.'
+ UNION ALL
+ SELECT N'@ExpertMode',
+ N'BIT',
+ N'0',
+ N'When set to 1, more checks are done. Examples: many to many merge joins, row goals, adaptive joins, stats info, bad scans and plan forcing, computed columns that reference scalar UDFs.'
+ UNION ALL
+ SELECT N'@VersionCheckMode',
+ N'BIT',
+ N'0',
+ N'Outputs the version number and date.'
+
+ /* Column definitions */
+ SELECT 'database_name' AS [Column Name],
+ 'NVARCHAR(258)' AS [Data Type],
+ 'The name of the database where the plan was encountered.' AS [Column Description]
+ UNION ALL
+ SELECT 'query_cost',
+ 'FLOAT',
+ 'The cost of the execution plan in query bucks.'
+ UNION ALL
+ SELECT 'plan_id',
+ 'BIGINT',
+ 'The ID of the plan from sys.query_store_plan.'
+ UNION ALL
+ SELECT 'query_id',
+ 'BIGINT',
+ 'The ID of the query from sys.query_store_query.'
+ UNION ALL
+ SELECT 'query_id_all_plan_ids',
+ 'VARCHAR(8000)',
+ 'Comma-separated list of all query plan IDs associated with this query.'
+ UNION ALL
+ SELECT 'query_sql_text',
+ 'NVARCHAR(MAX)',
+ 'The text of the query, as provided by the user/app. Includes whitespaces, hints and comments. Comments and spaces before and after the query text are ignored.'
+ UNION ALL
+ SELECT 'proc_or_function_name',
+ 'NVARCHAR(258)',
+ 'If the query is part of a function/stored procedure, you''ll see here the name of its parent object.'
+ UNION ALL
+ SELECT 'query_plan_xml',
+ ' XML',
+ 'The query plan. Click to display a graphical plan.'
+ UNION ALL
+ SELECT 'warnings',
+ 'VARCHAR(MAX)',
+ 'A list of individual warnings generated by this query.'
+ UNION ALL
+ SELECT 'pattern',
+ 'NVARCHAR(512)',
+ 'A list of performance related patterns identified for this query.'
+ UNION ALL
+ SELECT 'parameter_sniffing_symptoms',
+ 'NVARCHAR(4000)',
+ 'A list of all the identified symptoms that are usually indicators of parameter sniffing.'
+ UNION ALL
+ SELECT 'last_force_failure_reason_desc',
+ 'NVARCHAR(258)',
+ 'Reason why plan forcing failed. NONE if plan isn''t forced.'
+ UNION ALL
+ SELECT 'top_three_waits',
+ 'NVARCHAR(MAX)',
+ 'The top 3 wait types, and their times in milliseconds, recorded for this query.'
+ UNION ALL
+ SELECT 'missing_indexes',
+ 'XML',
+ 'Missing index recommendations retrieved from the query plan.'
+ UNION ALL
+ SELECT 'implicit_conversion_info',
+ 'XML',
+ 'Information about the implicit conversion warnings,if any, retrieved from the query plan.'
+ UNION ALL
+ SELECT 'cached_execution_parameters',
+ 'XML',
+ 'Names, data types, and values for the parameters used when the query plan was compiled.'
+ UNION ALL
+ SELECT 'count_executions ',
+ 'BIGINT',
+ 'The number of executions of this particular query.'
+ UNION ALL
+ SELECT 'count_compiles',
+ 'BIGINT',
+ 'The number of plan compilations for this particular query.'
+ UNION ALL
+ SELECT 'total_cpu_time',
+ 'BIGINT',
+ 'Total CPU time, reported in milliseconds, that was consumed by all executions of this query.'
+ UNION ALL
+ SELECT 'avg_cpu_time ',
+ 'BIGINT',
+ 'Average CPU time, reported in milliseconds, consumed by each execution of this query.'
+ UNION ALL
+ SELECT 'total_duration',
+ 'BIGINT',
+ 'Total elapsed time, reported in milliseconds, consumed by all executions of this query.'
+ UNION ALL
+ SELECT 'avg_duration',
+ 'BIGINT',
+ 'Average elapsed time, reported in milliseconds, consumed by each execution of this query.'
+ UNION ALL
+ SELECT 'total_logical_io_reads',
+ 'BIGINT',
+ 'Total logical reads, reported in MB, performed by this query.'
+ UNION ALL
+ SELECT 'avg_logical_io_reads',
+ 'BIGINT',
+ 'Average logical reads, reported in MB, performed by each execution of this query.'
+ UNION ALL
+ SELECT 'total_physical_io_reads',
+ 'BIGINT',
+ 'Total physical reads, reported in MB, performed by this query.'
+ UNION ALL
+ SELECT 'avg_physical_io_reads',
+ 'BIGINT',
+ 'Average physical reads, reported in MB, performed by each execution of this query.'
+ UNION ALL
+ SELECT 'total_logical_io_writes',
+ 'BIGINT',
+ 'Total logical writes, reported in MB, performed by this query.'
+ UNION ALL
+ SELECT 'avg_logical_io_writes',
+ 'BIGINT',
+ 'Average logical writes, reported in MB, performed by each execution of this query.'
+ UNION ALL
+ SELECT 'total_rowcount',
+ 'BIGINT',
+ 'Total number of rows returned for all executions of this query.'
+ UNION ALL
+ SELECT 'avg_rowcount',
+ 'BIGINT',
+ 'Average number of rows returned by each execution of this query.'
+ UNION ALL
+ SELECT 'total_query_max_used_memory',
+ 'DECIMAL(38,2)',
+ 'Total max memory grant, reported in MB, used by this query.'
+ UNION ALL
+ SELECT 'avg_query_max_used_memory',
+ 'DECIMAL(38,2)',
+ 'Average max memory grant, reported in MB, used by each execution of this query.'
+ UNION ALL
+ SELECT 'total_tempdb_space_used',
+ 'DECIMAL(38,2)',
+ 'Total tempdb space, reported in MB, used by this query.'
+ UNION ALL
+ SELECT 'avg_tempdb_space_used',
+ 'DECIMAL(38,2)',
+ 'Average tempdb space, reported in MB, used by each execution of this query.'
+ UNION ALL
+ SELECT 'total_log_bytes_used',
+ 'DECIMAL(38,2)',
+ 'Total number of bytes in the database log used by this query.'
+ UNION ALL
+ SELECT 'avg_log_bytes_used',
+ 'DECIMAL(38,2)',
+ 'Average number of bytes in the database log used by each execution of this query.'
+ UNION ALL
+ SELECT 'total_num_physical_io_reads',
+ 'DECIMAL(38,2)',
+ 'Total number of physical I/O reads performed by this query (expressed as a number of read I/O operations).'
+ UNION ALL
+ SELECT 'avg_num_physical_io_reads',
+ 'DECIMAL(38,2)',
+ 'Average number of physical I/O reads performed by each execution of this query (expressed as a number of read I/O operations).'
+ UNION ALL
+ SELECT 'first_execution_time',
+ 'DATETIME2',
+ 'First execution time for this query within the aggregation interval. This is the end time of the query execution.'
+ UNION ALL
+ SELECT 'last_execution_time',
+ 'DATETIME2',
+ 'Last execution time for this query within the aggregation interval. This is the end time of the query execution.'
+ UNION ALL
+ SELECT 'context_settings',
+ 'NVARCHAR(512)',
+ 'Contains information about context settings associated with this query.';
RETURN;
END;
@@ -36150,7 +36516,7 @@ BEGIN
SET STATISTICS XML OFF;
SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
- SELECT @Version = '8.17', @VersionDate = '20231010';
+ SELECT @Version = '8.18', @VersionDate = '20231222';
IF(@VersionCheckMode = 1)
BEGIN
@@ -37546,6 +37912,8 @@ DELETE FROM dbo.SqlServerVersions;
INSERT INTO dbo.SqlServerVersions
(MajorVersionNumber, MinorVersionNumber, Branch, [Url], ReleaseDate, MainstreamSupportEndDate, ExtendedSupportEndDate, MajorVersionName, MinorVersionName)
VALUES
+ (16, 4095, 'CU10', 'https://support.microsoft.com/en-us/help/5031778', '2023-11-16', '2028-01-11', '2033-01-11', 'SQL Server 2022', 'Cumulative Update 10'),
+ (16, 4085, 'CU9', 'https://support.microsoft.com/en-us/help/5030731', '2023-10-12', '2028-01-11', '2033-01-11', 'SQL Server 2022', 'Cumulative Update 9'),
(16, 4075, 'CU8', 'https://support.microsoft.com/en-us/help/5029666', '2023-09-14', '2028-01-11', '2033-01-11', 'SQL Server 2022', 'Cumulative Update 8'),
(16, 4065, 'CU7', 'https://support.microsoft.com/en-us/help/5028743', '2023-08-10', '2028-01-11', '2033-01-11', 'SQL Server 2022', 'Cumulative Update 7'),
(16, 4055, 'CU6', 'https://support.microsoft.com/en-us/help/5027505', '2023-07-13', '2028-01-11', '2033-01-11', 'SQL Server 2022', 'Cumulative Update 6'),
@@ -37556,6 +37924,8 @@ VALUES
(16, 4003, 'CU1', 'https://support.microsoft.com/en-us/help/5022375', '2023-02-16', '2028-01-11', '2033-01-11', 'SQL Server 2022', 'Cumulative Update 1'),
(16, 1050, 'RTM GDR', 'https://support.microsoft.com/kb/5021522', '2023-02-14', '2028-01-11', '2033-01-11', 'SQL Server 2022 GDR', 'RTM'),
(16, 1000, 'RTM', '', '2022-11-15', '2028-01-11', '2033-01-11', 'SQL Server 2022', 'RTM'),
+ (15, 4345, 'CU24', 'https://support.microsoft.com/kb/5031908', '2023-12-14', '2025-01-07', '2030-01-08', 'SQL Server 2019', 'Cumulative Update 24'),
+ (15, 4335, 'CU23', 'https://support.microsoft.com/kb/5030333', '2023-10-12', '2025-01-07', '2030-01-08', 'SQL Server 2019', 'Cumulative Update 23'),
(15, 4322, 'CU22', 'https://support.microsoft.com/kb/5027702', '2023-08-14', '2025-01-07', '2030-01-08', 'SQL Server 2019', 'Cumulative Update 22'),
(15, 4316, 'CU21', 'https://support.microsoft.com/kb/5025808', '2023-06-15', '2025-01-07', '2030-01-08', 'SQL Server 2019', 'Cumulative Update 21'),
(15, 4312, 'CU20', 'https://support.microsoft.com/kb/5024276', '2023-04-13', '2025-01-07', '2030-01-08', 'SQL Server 2019', 'Cumulative Update 20'),
@@ -37583,6 +37953,7 @@ VALUES
(15, 4003, 'CU1', 'https://support.microsoft.com/en-us/help/4527376', '2020-01-07', '2025-01-07', '2030-01-08', 'SQL Server 2019', 'Cumulative Update 1 '),
(15, 2070, 'GDR', 'https://support.microsoft.com/en-us/help/4517790', '2019-11-04', '2025-01-07', '2030-01-08', 'SQL Server 2019', 'RTM GDR '),
(15, 2000, 'RTM ', '', '2019-11-04', '2025-01-07', '2030-01-08', 'SQL Server 2019', 'RTM '),
+ (14, 3465, 'RTM CU31 GDR', 'https://support.microsoft.com/kb/5029376', '2023-10-12', '2022-10-11', '2027-10-12', 'SQL Server 2017', 'RTM Cumulative Update 31 GDR'),
(14, 3460, 'RTM CU31 GDR', 'https://support.microsoft.com/kb/5021126', '2023-02-14', '2022-10-11', '2027-10-12', 'SQL Server 2017', 'RTM Cumulative Update 31 GDR'),
(14, 3456, 'RTM CU31', 'https://support.microsoft.com/en-us/help/5016884', '2022-09-20', '2022-10-11', '2027-10-12', 'SQL Server 2017', 'RTM Cumulative Update 31'),
(14, 3451, 'RTM CU30', 'https://support.microsoft.com/en-us/help/5013756', '2022-07-13', '2022-10-11', '2027-10-12', 'SQL Server 2017', 'RTM Cumulative Update 30'),
@@ -37980,7 +38351,7 @@ SET NOCOUNT ON;
SET STATISTICS XML OFF;
SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
-SELECT @Version = '8.17', @VersionDate = '20231010';
+SELECT @Version = '8.18', @VersionDate = '20231222';
IF(@VersionCheckMode = 1)
BEGIN
diff --git a/SqlServerVersions.sql b/SqlServerVersions.sql
index ac7600d0..40aea38c 100644
--- a/SqlServerVersions.sql
+++ b/SqlServerVersions.sql
@@ -41,6 +41,8 @@ DELETE FROM dbo.SqlServerVersions;
INSERT INTO dbo.SqlServerVersions
(MajorVersionNumber, MinorVersionNumber, Branch, [Url], ReleaseDate, MainstreamSupportEndDate, ExtendedSupportEndDate, MajorVersionName, MinorVersionName)
VALUES
+ (16, 4095, 'CU10', 'https://support.microsoft.com/en-us/help/5031778', '2023-11-16', '2028-01-11', '2033-01-11', 'SQL Server 2022', 'Cumulative Update 10'),
+ (16, 4085, 'CU9', 'https://support.microsoft.com/en-us/help/5030731', '2023-10-12', '2028-01-11', '2033-01-11', 'SQL Server 2022', 'Cumulative Update 9'),
(16, 4075, 'CU8', 'https://support.microsoft.com/en-us/help/5029666', '2023-09-14', '2028-01-11', '2033-01-11', 'SQL Server 2022', 'Cumulative Update 8'),
(16, 4065, 'CU7', 'https://support.microsoft.com/en-us/help/5028743', '2023-08-10', '2028-01-11', '2033-01-11', 'SQL Server 2022', 'Cumulative Update 7'),
(16, 4055, 'CU6', 'https://support.microsoft.com/en-us/help/5027505', '2023-07-13', '2028-01-11', '2033-01-11', 'SQL Server 2022', 'Cumulative Update 6'),
@@ -51,6 +53,8 @@ VALUES
(16, 4003, 'CU1', 'https://support.microsoft.com/en-us/help/5022375', '2023-02-16', '2028-01-11', '2033-01-11', 'SQL Server 2022', 'Cumulative Update 1'),
(16, 1050, 'RTM GDR', 'https://support.microsoft.com/kb/5021522', '2023-02-14', '2028-01-11', '2033-01-11', 'SQL Server 2022 GDR', 'RTM'),
(16, 1000, 'RTM', '', '2022-11-15', '2028-01-11', '2033-01-11', 'SQL Server 2022', 'RTM'),
+ (15, 4345, 'CU24', 'https://support.microsoft.com/kb/5031908', '2023-12-14', '2025-01-07', '2030-01-08', 'SQL Server 2019', 'Cumulative Update 24'),
+ (15, 4335, 'CU23', 'https://support.microsoft.com/kb/5030333', '2023-10-12', '2025-01-07', '2030-01-08', 'SQL Server 2019', 'Cumulative Update 23'),
(15, 4322, 'CU22', 'https://support.microsoft.com/kb/5027702', '2023-08-14', '2025-01-07', '2030-01-08', 'SQL Server 2019', 'Cumulative Update 22'),
(15, 4316, 'CU21', 'https://support.microsoft.com/kb/5025808', '2023-06-15', '2025-01-07', '2030-01-08', 'SQL Server 2019', 'Cumulative Update 21'),
(15, 4312, 'CU20', 'https://support.microsoft.com/kb/5024276', '2023-04-13', '2025-01-07', '2030-01-08', 'SQL Server 2019', 'Cumulative Update 20'),
@@ -78,6 +82,7 @@ VALUES
(15, 4003, 'CU1', 'https://support.microsoft.com/en-us/help/4527376', '2020-01-07', '2025-01-07', '2030-01-08', 'SQL Server 2019', 'Cumulative Update 1 '),
(15, 2070, 'GDR', 'https://support.microsoft.com/en-us/help/4517790', '2019-11-04', '2025-01-07', '2030-01-08', 'SQL Server 2019', 'RTM GDR '),
(15, 2000, 'RTM ', '', '2019-11-04', '2025-01-07', '2030-01-08', 'SQL Server 2019', 'RTM '),
+ (14, 3465, 'RTM CU31 GDR', 'https://support.microsoft.com/kb/5029376', '2023-10-12', '2022-10-11', '2027-10-12', 'SQL Server 2017', 'RTM Cumulative Update 31 GDR'),
(14, 3460, 'RTM CU31 GDR', 'https://support.microsoft.com/kb/5021126', '2023-02-14', '2022-10-11', '2027-10-12', 'SQL Server 2017', 'RTM Cumulative Update 31 GDR'),
(14, 3456, 'RTM CU31', 'https://support.microsoft.com/en-us/help/5016884', '2022-09-20', '2022-10-11', '2027-10-12', 'SQL Server 2017', 'RTM Cumulative Update 31'),
(14, 3451, 'RTM CU30', 'https://support.microsoft.com/en-us/help/5013756', '2022-07-13', '2022-10-11', '2027-10-12', 'SQL Server 2017', 'RTM Cumulative Update 30'),
diff --git a/sp_AllNightLog.sql b/sp_AllNightLog.sql
index da4cf313..1e7b1ddd 100644
--- a/sp_AllNightLog.sql
+++ b/sp_AllNightLog.sql
@@ -31,7 +31,7 @@ SET STATISTICS XML OFF;
BEGIN;
-SELECT @Version = '8.17', @VersionDate = '20231010';
+SELECT @Version = '8.18', @VersionDate = '20231222';
IF(@VersionCheckMode = 1)
BEGIN
diff --git a/sp_AllNightLog_Setup.sql b/sp_AllNightLog_Setup.sql
index cfc2042f..8238c897 100644
--- a/sp_AllNightLog_Setup.sql
+++ b/sp_AllNightLog_Setup.sql
@@ -38,7 +38,7 @@ SET STATISTICS XML OFF;
BEGIN;
-SELECT @Version = '8.17', @VersionDate = '20231010';
+SELECT @Version = '8.18', @VersionDate = '20231222';
IF(@VersionCheckMode = 1)
BEGIN
diff --git a/sp_Blitz.sql b/sp_Blitz.sql
index 08a6ca91..9804f45d 100644
--- a/sp_Blitz.sql
+++ b/sp_Blitz.sql
@@ -38,7 +38,7 @@ AS
SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
- SELECT @Version = '8.17', @VersionDate = '20231010';
+ SELECT @Version = '8.18', @VersionDate = '20231222';
SET @OutputType = UPPER(@OutputType);
IF(@VersionCheckMode = 1)
@@ -196,14 +196,11 @@ AS
,@SkipXPFixedDrives bit = 0
,@SkipXPCMDShell bit = 0
,@SkipMaster bit = 0
- ,@SkipMSDB bit = 0
+ ,@SkipMSDB_objs bit = 0
+ ,@SkipMSDB_jobs bit = 0
,@SkipModel bit = 0
,@SkipTempDB bit = 0
,@SkipValidateLogins bit = 0
- /* Variables for check 211: */
- ,@powerScheme varchar(36)
- ,@cpu_speed_mhz int
- ,@cpu_speed_ghz decimal(18,2);
DECLARE
@db_perms table
@@ -278,38 +275,6 @@ AS
SET @SkipTrace = 1;
END; /*We need this permission to execute trace stuff, apparently*/
- IF ISNULL(@SkipXPRegRead, 0) != 1 /*If @SkipXPRegRead hasn't been set to 1 by the caller*/
- BEGIN
- BEGIN TRY
- /* Get power plan if set by group policy [Git Hub Issue #1620] */
- EXEC xp_regread @rootkey = N'HKEY_LOCAL_MACHINE',
- @key = N'SOFTWARE\Policies\Microsoft\Power\PowerSettings',
- @value_name = N'ActivePowerScheme',
- @value = @powerScheme OUTPUT,
- @no_output = N'no_output';
-
- IF @powerScheme IS NULL /* If power plan was not set by group policy, get local value [Git Hub Issue #1620]*/
- EXEC xp_regread @rootkey = N'HKEY_LOCAL_MACHINE',
- @key = N'SYSTEM\CurrentControlSet\Control\Power\User\PowerSchemes',
- @value_name = N'ActivePowerScheme',
- @value = @powerScheme OUTPUT;
-
- /* Get the cpu speed*/
- EXEC xp_regread @rootkey = N'HKEY_LOCAL_MACHINE',
- @key = N'HARDWARE\DESCRIPTION\System\CentralProcessor\0',
- @value_name = N'~MHz',
- @value = @cpu_speed_mhz OUTPUT;
-
- /* Convert the Megahertz to Gigahertz */
- SET @cpu_speed_ghz = CAST(CAST(@cpu_speed_mhz AS decimal) / 1000 AS decimal(18,2));
-
- SET @SkipXPRegRead = 0; /*We could execute xp_regread*/
- END TRY
- BEGIN CATCH
- SET @SkipXPRegRead = 1; /*We have don't have execute rights or xp_regread throws an error so skip it*/
- END CATCH;
- END; /*Need execute on xp_regread*/
-
IF NOT EXISTS
(
SELECT
@@ -379,7 +344,7 @@ AS
END;
END;
- IF ISNULL(@SkipMSDB, 0) != 1 /*If @SkipMSDB hasn't been set to 1 by the caller*/
+ IF ISNULL(@SkipMSDB_objs, 0) != 1 /*If @SkipMSDB_objs hasn't been set to 1 by the caller*/
BEGIN
IF EXISTS
(
@@ -395,16 +360,45 @@ AS
FROM msdb.sys.objects
)
BEGIN
- SET @SkipMSDB = 0; /*We have read permissions in the msdb database, and can view the objects*/
+ SET @SkipMSDB_objs = 0; /*We have read permissions in the msdb database, and can view the objects*/
END;
END TRY
BEGIN CATCH
- SET @SkipMSDB = 1; /*We have read permissions in the msdb database ... oh wait we got tricked, we can't view the objects*/
+ SET @SkipMSDB_objs = 1; /*We have read permissions in the msdb database ... oh wait we got tricked, we can't view the objects*/
END CATCH;
END;
ELSE
BEGIN
- SET @SkipMSDB = 1; /*We don't have read permissions in the msdb database*/
+ SET @SkipMSDB_objs = 1; /*We don't have read permissions in the msdb database*/
+ END;
+ END;
+
+ IF ISNULL(@SkipMSDB_jobs, 0) != 1 /*If @SkipMSDB_jobs hasn't been set to 1 by the caller*/
+ BEGIN
+ IF EXISTS
+ (
+ SELECT 1/0
+ FROM @db_perms
+ WHERE database_name = N'msdb'
+ )
+ BEGIN
+ BEGIN TRY
+ IF EXISTS
+ (
+ SELECT 1/0
+ FROM msdb.dbo.sysjobs
+ )
+ BEGIN
+ SET @SkipMSDB_jobs = 0; /*We have read permissions in the msdb database, and can view the objects*/
+ END;
+ END TRY
+ BEGIN CATCH
+ SET @SkipMSDB_jobs = 1; /*We have read permissions in the msdb database ... oh wait we got tricked, we can't view the objects*/
+ END CATCH;
+ END;
+ ELSE
+ BEGIN
+ SET @SkipMSDB_jobs = 1; /*We don't have read permissions in the msdb database*/
END;
END;
END;
@@ -576,17 +570,34 @@ AS
INSERT #SkipChecks (DatabaseName, CheckID, ServerName)
SELECT
v.*
- FROM (VALUES(NULL, 6, NULL), /*Jobs Owned By Users*/
- (NULL, 28, NULL), /*SQL Agent Job Runs at Startup*/
- (NULL, 57, NULL), /*Tables in the MSDB Database*/
+ FROM (VALUES(NULL, 28, NULL)) AS v (DatabaseName, CheckID, ServerName) /*Tables in the MSDB Database*/
+ WHERE @SkipMSDB_objs = 1;
+
+ INSERT #SkipChecks (DatabaseName, CheckID, ServerName)
+ SELECT
+ v.*
+ FROM (VALUES
+ /*sysjobs checks*/
+ (NULL, 6, NULL), /*Jobs Owned By Users*/
+ (NULL, 57, NULL), /*SQL Agent Job Runs at Startup*/
(NULL, 79, NULL), /*Shrink Database Job*/
(NULL, 94, NULL), /*Agent Jobs Without Failure Emails*/
(NULL, 123, NULL), /*Agent Jobs Starting Simultaneously*/
(NULL, 180, NULL), /*Shrink Database Step In Maintenance Plan*/
(NULL, 181, NULL), /*Repetitive Maintenance Tasks*/
- (NULL, 219, NULL) /*Alerts Without Event Descriptions*/
- ) AS v (DatabaseName, CheckID, ServerName)
- WHERE @SkipMSDB = 1;
+
+ /*sysalerts checks*/
+ (NULL, 30, NULL), /*Not All Alerts Configured*/
+ (NULL, 59, NULL), /*Alerts Configured without Follow Up*/
+ (NULL, 61, NULL), /*No Alerts for Sev 19-25*/
+ (NULL, 96, NULL), /*No Alerts for Corruption*/
+ (NULL, 98, NULL), /*Alerts Disabled*/
+ (NULL, 219, NULL), /*Alerts Without Event Descriptions*/
+
+ /*sysoperators*/
+ (NULL, 31, NULL) /*No Operators Configured/Enabled*/
+ ) AS v (DatabaseName, CheckID, ServerName)
+ WHERE @SkipMSDB_jobs = 1;
INSERT #SkipChecks (DatabaseName, CheckID, ServerName)
SELECT
@@ -630,6 +641,25 @@ AS
FROM (VALUES(NULL, 2301, NULL)) AS v (DatabaseName, CheckID, ServerName) /*sp_validatelogins*/
WHERE @SkipValidateLogins = 1
+ IF @sa = 0
+ BEGIN
+ INSERT INTO #BlitzResults
+ ( CheckID ,
+ Priority ,
+ FindingsGroup ,
+ Finding ,
+ URL ,
+ Details
+ )
+ SELECT 223 AS CheckID ,
+ 0 AS Priority ,
+ 'Informational' AS FindingsGroup ,
+ 'Some Checks Skipped' AS Finding ,
+ '' AS URL ,
+ 'User ''' + @SUSER_NAME + ''' is not part of the sysadmin role, so we skipped some checks that are not possible due to lack of permissions.' AS Details;
+ END;
+ /*End of SkipsChecks added due to permissions*/
+
IF @SkipChecksTable IS NOT NULL
AND @SkipChecksSchema IS NOT NULL
AND @SkipChecksDatabase IS NOT NULL
@@ -8674,122 +8704,147 @@ IF @ProductVersionMajor >= 10 AND NOT EXISTS ( SELECT 1
EXECUTE(@StringToExecute);
END;
- /*
- Starting with SQL Server 2014 SP2, Instant File Initialization
- is logged in the SQL Server Error Log.
- */
- IF NOT EXISTS ( SELECT 1
- FROM #SkipChecks
- WHERE DatabaseName IS NULL AND CheckID = 193 )
- AND ((@ProductVersionMajor >= 13) OR (@ProductVersionMajor = 12 AND @ProductVersionMinor >= 5000))
+ /* Performance - Instant File Initialization Not Enabled - Check 192 */
+ /* Server Info - Instant File Initialization Enabled - Check 193 */
+ IF NOT EXISTS ( SELECT 1/0
+ FROM #SkipChecks
+ WHERE DatabaseName IS NULL AND CheckID = 192 /* IFI disabled check disabled */
+ ) OR NOT EXISTS
+ ( SELECT 1/0
+ FROM #SkipChecks
+ WHERE DatabaseName IS NULL AND CheckID = 193 /* IFI enabled check disabled */
+ )
+ BEGIN
+ IF @Debug IN (1, 2) RAISERROR('Running CheckId [%d] and CheckId [%d].', 0, 1, 192, 193) WITH NOWAIT;
+
+ DECLARE @IFISetting varchar(1) = N'N'
+ ,@IFIReadDMVFailed bit = 0
+ ,@IFIAllFailed bit = 0;
+
+ /* See if we can get the instant_file_initialization_enabled column from sys.dm_server_services */
+ IF EXISTS
+ (
+ SELECT 1/0
+ FROM sys.all_columns
+ WHERE [object_id] = OBJECT_ID(N'[sys].[dm_server_services]')
+ AND [name] = N'instant_file_initialization_enabled'
+ )
BEGIN
+ /* This needs to be a "dynamic" SQL statement because if the 'instant_file_initialization_enabled' column doesn't exist the procedure might fail on a bind error */
+ SET @StringToExecute = N'SELECT @IFISetting = instant_file_initialization_enabled' + @crlf +
+ N'FROM sys.dm_server_services' + @crlf +
+ N'WHERE filename LIKE ''%sqlservr.exe%''' + @crlf +
+ N'OPTION (RECOMPILE);';
+
+ IF @Debug = 2 AND @StringToExecute IS NOT NULL PRINT @StringToExecute;
+ IF @Debug = 2 AND @StringToExecute IS NULL PRINT '@StringToExecute has gone NULL, for some reason.';
+
+ EXEC dbo.sp_executesql
+ @StringToExecute
+ ,N'@IFISetting varchar(1) OUTPUT'
+ ,@IFISetting = @IFISetting OUTPUT
- IF @Debug IN (1, 2) RAISERROR('Running CheckId [%d].', 0, 1, 193) WITH NOWAIT;
-
- -- If this is Amazon RDS, use rdsadmin.dbo.rds_read_error_log
- IF LEFT(CAST(SERVERPROPERTY('ComputerNamePhysicalNetBIOS') AS VARCHAR(8000)), 8) = 'EC2AMAZ-'
- AND LEFT(CAST(SERVERPROPERTY('MachineName') AS VARCHAR(8000)), 8) = 'EC2AMAZ-'
- AND db_id('rdsadmin') IS NOT NULL
- AND EXISTS(SELECT * FROM master.sys.all_objects WHERE name IN ('rds_startup_tasks', 'rds_help_revlogin', 'rds_hexadecimal', 'rds_failover_tracking', 'rds_database_tracking', 'rds_track_change'))
- BEGIN
- INSERT INTO #ErrorLog
- EXEC rdsadmin.dbo.rds_read_error_log 0, 1, N'Database Instant File Initialization: enabled';
- END
- ELSE
- BEGIN
- BEGIN TRY
- INSERT INTO #ErrorLog
- EXEC sys.xp_readerrorlog 0, 1, N'Database Instant File Initialization: enabled';
- END TRY
- BEGIN CATCH
- IF @Debug IN (1, 2) RAISERROR('No permissions to execute xp_readerrorlog.', 0, 1) WITH NOWAIT;
- END CATCH
- END
-
- IF EXISTS
- (
- SELECT 1/0
- FROM #ErrorLog
- WHERE LEFT([Text], 45) = N'Database Instant File Initialization: enabled'
- )
- BEGIN
- INSERT INTO #BlitzResults
- ( CheckID ,
- [Priority] ,
- FindingsGroup ,
- Finding ,
- URL ,
- Details
- )
- SELECT
- 193 AS [CheckID] ,
- 250 AS [Priority] ,
- 'Server Info' AS [FindingsGroup] ,
- 'Instant File Initialization Enabled' AS [Finding] ,
- 'https://www.brentozar.com/go/instant' AS [URL] ,
- 'The service account has the Perform Volume Maintenance Tasks permission.';
- END;
- else -- if version of sql server has instant_file_initialization_enabled column in dm_server_services, check that too
- -- in the event the error log has been cycled and the startup messages are not in the current error log
- begin
- 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_server_services'
- AND c.name = 'instant_file_initialization_enabled' )
- begin
- SET @StringToExecute = N'
- INSERT INTO #BlitzResults
- ( CheckID ,
- [Priority] ,
- FindingsGroup ,
- Finding ,
- URL ,
- Details
- )
- SELECT
- 193 AS [CheckID] ,
- 250 AS [Priority] ,
- ''Server Info'' AS [FindingsGroup] ,
- ''Instant File Initialization Enabled'' AS [Finding] ,
- ''https://www.brentozar.com/go/instant'' AS [URL] ,
- ''The service account has the Perform Volume Maintenance Tasks permission.''
- where exists (select 1 FROM sys.dm_server_services
- WHERE instant_file_initialization_enabled = ''Y''
- AND filename LIKE ''%sqlservr.exe%'')
- OPTION (RECOMPILE);';
- EXEC(@StringToExecute);
- end;
- end;
- END;
+ SET @IFIReadDMVFailed = 0;
+ END
+ ELSE
+ /* We couldn't get the instant_file_initialization_enabled column from sys.dm_server_services, fall back to read error log */
+ BEGIN
+ SET @IFIReadDMVFailed = 1;
+ /* If this is Amazon RDS, we'll use the rdsadmin.dbo.rds_read_error_log */
+ IF LEFT(CAST(SERVERPROPERTY('ComputerNamePhysicalNetBIOS') AS VARCHAR(8000)), 8) = 'EC2AMAZ-'
+ AND LEFT(CAST(SERVERPROPERTY('MachineName') AS VARCHAR(8000)), 8) = 'EC2AMAZ-'
+ AND db_id('rdsadmin') IS NOT NULL
+ AND EXISTS ( SELECT 1/0
+ FROM master.sys.all_objects
+ WHERE name IN ('rds_startup_tasks', 'rds_help_revlogin', 'rds_hexadecimal', 'rds_failover_tracking', 'rds_database_tracking', 'rds_track_change')
+ )
+ BEGIN
+ /* Amazon RDS detected, read rdsadmin.dbo.rds_read_error_log */
+ INSERT INTO #ErrorLog
+ EXEC rdsadmin.dbo.rds_read_error_log 0, 1, N'Database Instant File Initialization: enabled';
+ END
+ ELSE
+ BEGIN
+ /* Try to read the error log, this might fail due to permissions */
+ BEGIN TRY
+ INSERT INTO #ErrorLog
+ EXEC sys.xp_readerrorlog 0, 1, N'Database Instant File Initialization: enabled';
+ END TRY
+ BEGIN CATCH
+ IF @Debug IN (1, 2) RAISERROR('No permissions to execute xp_readerrorlog.', 0, 1) WITH NOWAIT;
+ SET @IFIAllFailed = 1;
+ END CATCH
+ END;
+ END;
+
+ IF @IFIAllFailed = 0
+ BEGIN
+ IF @IFIReadDMVFailed = 1
+ /* We couldn't read the DMV so set the @IFISetting variable using the error log */
+ BEGIN
+ IF EXISTS ( SELECT 1/0
+ FROM #ErrorLog
+ WHERE LEFT([Text], 45) = N'Database Instant File Initialization: enabled'
+ )
+ BEGIN
+ SET @IFISetting = 'Y';
+ END
+ ELSE
+ BEGIN
+ SET @IFISetting = 'N';
+ END;
+ END;
+
+ IF NOT EXISTS ( SELECT 1/0
+ FROM #SkipChecks
+ WHERE DatabaseName IS NULL AND CheckID = 192 /* IFI disabled check disabled */
+ ) AND @IFISetting = 'N'
+ BEGIN
+ INSERT INTO #BlitzResults
+ (
+ CheckID ,
+ [Priority] ,
+ FindingsGroup ,
+ Finding ,
+ URL ,
+ Details
+ )
+ SELECT
+ 192 AS [CheckID] ,
+ 50 AS [Priority] ,
+ 'Performance' AS [FindingsGroup] ,
+ 'Instant File Initialization Not Enabled' AS [Finding] ,
+ 'https://www.brentozar.com/go/instant' AS [URL] ,
+ 'Consider enabling IFI for faster restores and data file growths.' AS [Details]
+ END;
+
+ IF NOT EXISTS ( SELECT 1/0
+ FROM #SkipChecks
+ WHERE DatabaseName IS NULL AND CheckID = 193 /* IFI enabled check disabled */
+ ) AND @IFISetting = 'Y'
+ BEGIN
+ INSERT INTO #BlitzResults
+ (
+ CheckID ,
+ [Priority] ,
+ FindingsGroup ,
+ Finding ,
+ URL ,
+ Details
+ )
+ SELECT
+ 193 AS [CheckID] ,
+ 250 AS [Priority] ,
+ 'Server Info' AS [FindingsGroup] ,
+ 'Instant File Initialization Enabled' AS [Finding] ,
+ 'https://www.brentozar.com/go/instant' AS [URL] ,
+ 'The service account has the Perform Volume Maintenance Tasks permission.' AS [Details]
+ END;
+ END;
+ END;
- /* Server Info - Instant File Initialization Not Enabled - Check 192 - SQL Server 2016 SP1 and newer */
- IF NOT EXISTS ( SELECT 1
- FROM #SkipChecks
- WHERE DatabaseName IS NULL AND CheckID = 192 )
- AND EXISTS ( SELECT *
- FROM sys.all_objects o
- INNER JOIN sys.all_columns c ON o.object_id = c.object_id
- WHERE o.name = 'dm_server_services'
- AND c.name = 'instant_file_initialization_enabled' )
- BEGIN
-
- IF @Debug IN (1, 2) RAISERROR('Running CheckId [%d].', 0, 1, 192) WITH NOWAIT;
-
- SET @StringToExecute = 'INSERT INTO #BlitzResults (CheckID, Priority, FindingsGroup, Finding, URL, Details)
- SELECT 192 AS CheckID ,
- 50 AS Priority ,
- ''Server Info'' AS FindingsGroup ,
- ''Instant File Initialization Not Enabled'' AS Finding ,
- ''https://www.brentozar.com/go/instant'' AS URL ,
- ''Consider enabling IFI for faster restores and data file growths.''
- FROM sys.dm_server_services WHERE instant_file_initialization_enabled <> ''Y'' AND filename LIKE ''%sqlservr.exe%'' OPTION (RECOMPILE);';
-
- IF @Debug = 2 AND @StringToExecute IS NOT NULL PRINT @StringToExecute;
- IF @Debug = 2 AND @StringToExecute IS NULL PRINT '@StringToExecute has gone NULL, for some reason.';
-
- EXECUTE(@StringToExecute);
- END;
+ /* End of checkId 192 */
+ /* End of checkId 193 */
IF NOT EXISTS ( SELECT 1
FROM #SkipChecks
@@ -9167,7 +9222,39 @@ IF @ProductVersionMajor >= 10 AND NOT EXISTS ( SELECT 1
WHERE DatabaseName IS NULL AND CheckID = 211 )
BEGIN
+ /* Variables for check 211: */
+ DECLARE
+ @powerScheme varchar(36)
+ ,@cpu_speed_mhz int
+ ,@cpu_speed_ghz decimal(18,2)
+ ,@ExecResult int;
+
IF @Debug IN (1, 2) RAISERROR('Running CheckId [%d].', 0, 1, 211) WITH NOWAIT;
+ IF @sa = 0 RAISERROR('The errors: ''xp_regread() returned error 5, ''Access is denied.'''' can be safely ignored', 0, 1) WITH NOWAIT;
+
+ /* Get power plan if set by group policy [Git Hub Issue #1620] */
+ EXEC xp_regread @rootkey = N'HKEY_LOCAL_MACHINE',
+ @key = N'SOFTWARE\Policies\Microsoft\Power\PowerSettings',
+ @value_name = N'ActivePowerScheme',
+ @value = @powerScheme OUTPUT,
+ @no_output = N'no_output';
+
+ IF @powerScheme IS NULL /* If power plan was not set by group policy, get local value [Git Hub Issue #1620]*/
+ EXEC xp_regread @rootkey = N'HKEY_LOCAL_MACHINE',
+ @key = N'SYSTEM\CurrentControlSet\Control\Power\User\PowerSchemes',
+ @value_name = N'ActivePowerScheme',
+ @value = @powerScheme OUTPUT;
+
+ /* Get the cpu speed*/
+ EXEC @ExecResult = xp_regread @rootkey = N'HKEY_LOCAL_MACHINE',
+ @key = N'HARDWARE\DESCRIPTION\System\CentralProcessor\0',
+ @value_name = N'~MHz',
+ @value = @cpu_speed_mhz OUTPUT;
+
+ /* Convert the Megahertz to Gigahertz */
+ IF @ExecResult != 0 RAISERROR('We couldn''t retrieve the CPU speed, you will see Unknown in the results', 0, 1)
+
+ SET @cpu_speed_ghz = CAST(CAST(@cpu_speed_mhz AS decimal) / 1000 AS decimal(18,2));
INSERT INTO #BlitzResults
( CheckID ,
@@ -9183,7 +9270,7 @@ IF @ProductVersionMajor >= 10 AND NOT EXISTS ( SELECT 1
'Power Plan' AS Finding,
'https://www.brentozar.com/blitz/power-mode/' AS URL,
'Your server has '
- + CAST(@cpu_speed_ghz as VARCHAR(4))
+ + ISNULL(CAST(@cpu_speed_ghz as VARCHAR(8)), 'Unknown ')
+ 'GHz CPUs, and is in '
+ CASE @powerScheme
WHEN 'a1841308-3541-4fab-bc81-f71556f20b4a'
@@ -9839,20 +9926,22 @@ IF @ProductVersionMajor >= 10 AND NOT EXISTS ( SELECT 1
FROM #BlitzResults
WHERE Priority > 0 AND Priority < 255 AND FindingsGroup IS NOT NULL AND Finding IS NOT NULL
AND FindingsGroup <> 'Security' /* Specifically excluding security checks for public exports */)
- SELECT
- CASE
- WHEN r.Priority <> COALESCE(rPrior.Priority, 0) OR r.FindingsGroup <> rPrior.FindingsGroup THEN @crlf + N'**Priority ' + CAST(COALESCE(r.Priority,N'') AS NVARCHAR(5)) + N': ' + COALESCE(r.FindingsGroup,N'') + N'**:' + @crlf + @crlf
- ELSE N''
- END
- + CASE WHEN r.Finding <> COALESCE(rPrior.Finding,N'') AND r.Finding <> COALESCE(rNext.Finding,N'') THEN N'- ' + COALESCE(r.Finding,N'') + N' ' + COALESCE(r.DatabaseName, N'') + N' - ' + COALESCE(r.Details,N'') + @crlf
- WHEN r.Finding <> COALESCE(rPrior.Finding,N'') AND r.Finding = rNext.Finding AND r.Details = rNext.Details THEN N'- ' + COALESCE(r.Finding,N'') + N' - ' + COALESCE(r.Details,N'') + @crlf + @crlf + N' * ' + COALESCE(r.DatabaseName, N'') + @crlf
- WHEN r.Finding <> COALESCE(rPrior.Finding,N'') AND r.Finding = rNext.Finding THEN N'- ' + COALESCE(r.Finding,N'') + @crlf + CASE WHEN r.DatabaseName IS NULL THEN N'' ELSE N' * ' + COALESCE(r.DatabaseName,N'') END + CASE WHEN r.Details <> rPrior.Details THEN N' - ' + COALESCE(r.Details,N'') + @crlf ELSE '' END
- ELSE CASE WHEN r.DatabaseName IS NULL THEN N'' ELSE N' * ' + COALESCE(r.DatabaseName,N'') END + CASE WHEN r.Details <> rPrior.Details THEN N' - ' + COALESCE(r.Details,N'') + @crlf ELSE N'' + @crlf END
- END + @crlf
- FROM Results r
- LEFT OUTER JOIN Results rPrior ON r.rownum = rPrior.rownum + 1
- LEFT OUTER JOIN Results rNext ON r.rownum = rNext.rownum - 1
- ORDER BY r.rownum FOR XML PATH(N'');
+ SELECT
+ Markdown = CONVERT(XML, STUFF((SELECT
+ CASE
+ WHEN r.Priority <> COALESCE(rPrior.Priority, 0) OR r.FindingsGroup <> rPrior.FindingsGroup THEN @crlf + N'**Priority ' + CAST(COALESCE(r.Priority,N'') AS NVARCHAR(5)) + N': ' + COALESCE(r.FindingsGroup,N'') + N'**:' + @crlf + @crlf
+ ELSE N''
+ END
+ + CASE WHEN r.Finding <> COALESCE(rPrior.Finding,N'') AND r.Finding <> COALESCE(rNext.Finding,N'') THEN N'- ' + COALESCE(r.Finding,N'') + N' ' + COALESCE(r.DatabaseName, N'') + N' - ' + COALESCE(r.Details,N'') + @crlf
+ WHEN r.Finding <> COALESCE(rPrior.Finding,N'') AND r.Finding = rNext.Finding AND r.Details = rNext.Details THEN N'- ' + COALESCE(r.Finding,N'') + N' - ' + COALESCE(r.Details,N'') + @crlf + @crlf + N' * ' + COALESCE(r.DatabaseName, N'') + @crlf
+ WHEN r.Finding <> COALESCE(rPrior.Finding,N'') AND r.Finding = rNext.Finding THEN N'- ' + COALESCE(r.Finding,N'') + @crlf + @crlf + CASE WHEN r.DatabaseName IS NULL THEN N'' ELSE N' * ' + COALESCE(r.DatabaseName,N'') END + CASE WHEN r.Details <> rPrior.Details THEN N' - ' + COALESCE(r.Details,N'') + @crlf ELSE '' END
+ ELSE CASE WHEN r.DatabaseName IS NULL THEN N'' ELSE N' * ' + COALESCE(r.DatabaseName,N'') END + CASE WHEN r.Details <> rPrior.Details THEN N' - ' + COALESCE(r.Details,N'') + @crlf ELSE N'' + @crlf END
+ END + @crlf
+ FROM Results r
+ LEFT OUTER JOIN Results rPrior ON r.rownum = rPrior.rownum + 1
+ LEFT OUTER JOIN Results rNext ON r.rownum = rNext.rownum - 1
+ ORDER BY r.rownum FOR XML PATH(N''), ROOT('Markdown'), TYPE).value('/Markdown[1]','VARCHAR(MAX)'), 1, 2, '')
+ + '');
END;
ELSE IF @OutputType = 'XML'
BEGIN
@@ -9976,4 +10065,4 @@ EXEC [dbo].[sp_Blitz]
@OutputProcedureCache = 0 ,
@CheckProcedureCacheFilter = NULL,
@CheckServerInfo = 1
-*/
+*/
\ No newline at end of file
diff --git a/sp_BlitzAnalysis.sql b/sp_BlitzAnalysis.sql
index e7ebb1df..f96c56b9 100644
--- a/sp_BlitzAnalysis.sql
+++ b/sp_BlitzAnalysis.sql
@@ -37,7 +37,7 @@ AS
SET NOCOUNT ON;
SET STATISTICS XML OFF;
-SELECT @Version = '8.17', @VersionDate = '20231010';
+SELECT @Version = '8.18', @VersionDate = '20231222';
IF(@VersionCheckMode = 1)
BEGIN
diff --git a/sp_BlitzBackups.sql b/sp_BlitzBackups.sql
index 1f31ddaa..b11b48d2 100755
--- a/sp_BlitzBackups.sql
+++ b/sp_BlitzBackups.sql
@@ -24,7 +24,7 @@ AS
SET STATISTICS XML OFF;
SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
- SELECT @Version = '8.17', @VersionDate = '20231010';
+ SELECT @Version = '8.18', @VersionDate = '20231222';
IF(@VersionCheckMode = 1)
BEGIN
diff --git a/sp_BlitzCache.sql b/sp_BlitzCache.sql
index 5c7fb2dc..07b3e1ab 100644
--- a/sp_BlitzCache.sql
+++ b/sp_BlitzCache.sql
@@ -281,7 +281,7 @@ SET NOCOUNT ON;
SET STATISTICS XML OFF;
SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
-SELECT @Version = '8.17', @VersionDate = '20231010';
+SELECT @Version = '8.18', @VersionDate = '20231222';
SET @OutputType = UPPER(@OutputType);
IF(@VersionCheckMode = 1)
@@ -7338,16 +7338,16 @@ END ';
IF @Debug = 1
BEGIN
- PRINT SUBSTRING(@StringToExecute, 0, 4000);
- PRINT SUBSTRING(@StringToExecute, 4000, 8000);
- PRINT SUBSTRING(@StringToExecute, 8000, 12000);
- PRINT SUBSTRING(@StringToExecute, 12000, 16000);
- PRINT SUBSTRING(@StringToExecute, 16000, 20000);
- PRINT SUBSTRING(@StringToExecute, 20000, 24000);
- PRINT SUBSTRING(@StringToExecute, 24000, 28000);
- PRINT SUBSTRING(@StringToExecute, 28000, 32000);
- PRINT SUBSTRING(@StringToExecute, 32000, 36000);
- PRINT SUBSTRING(@StringToExecute, 36000, 40000);
+ PRINT SUBSTRING(@StringToExecute, 1, 4000);
+ PRINT SUBSTRING(@StringToExecute, 4001, 4000);
+ PRINT SUBSTRING(@StringToExecute, 8001, 4000);
+ PRINT SUBSTRING(@StringToExecute, 12001, 4000);
+ PRINT SUBSTRING(@StringToExecute, 16001, 4000);
+ PRINT SUBSTRING(@StringToExecute, 20001, 4000);
+ PRINT SUBSTRING(@StringToExecute, 24001, 4000);
+ PRINT SUBSTRING(@StringToExecute, 28001, 4000);
+ PRINT SUBSTRING(@StringToExecute, 32001, 4000);
+ PRINT SUBSTRING(@StringToExecute, 36001, 4000);
END;
EXEC sp_executesql @StringToExecute, N'@Top INT, @min_duration INT, @min_back INT, @CheckDateOverride DATETIMEOFFSET, @MinimumExecutionCount INT', @Top, @DurationFilter_i, @MinutesBack, @CheckDateOverride, @MinimumExecutionCount;
diff --git a/sp_BlitzFirst.sql b/sp_BlitzFirst.sql
index a35db05c..3b1624e6 100644
--- a/sp_BlitzFirst.sql
+++ b/sp_BlitzFirst.sql
@@ -47,7 +47,7 @@ SET NOCOUNT ON;
SET STATISTICS XML OFF;
SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
-SELECT @Version = '8.17', @VersionDate = '20231010';
+SELECT @Version = '8.18', @VersionDate = '20231222';
IF(@VersionCheckMode = 1)
BEGIN
diff --git a/sp_BlitzInMemoryOLTP.sql b/sp_BlitzInMemoryOLTP.sql
index f2294de1..fc56a3cc 100644
--- a/sp_BlitzInMemoryOLTP.sql
+++ b/sp_BlitzInMemoryOLTP.sql
@@ -82,7 +82,7 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI
*/
AS
DECLARE @ScriptVersion VARCHAR(30);
-SELECT @ScriptVersion = '1.8', @VersionDate = '20231010';
+SELECT @ScriptVersion = '1.8', @VersionDate = '20231222';
IF(@VersionCheckMode = 1)
BEGIN
diff --git a/sp_BlitzIndex.sql b/sp_BlitzIndex.sql
index 0798e1d2..0e23b24f 100644
--- a/sp_BlitzIndex.sql
+++ b/sp_BlitzIndex.sql
@@ -48,7 +48,7 @@ SET NOCOUNT ON;
SET STATISTICS XML OFF;
SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
-SELECT @Version = '8.17', @VersionDate = '20231010';
+SELECT @Version = '8.18', @VersionDate = '20231222';
SET @OutputType = UPPER(@OutputType);
IF(@VersionCheckMode = 1)
@@ -1214,16 +1214,16 @@ BEGIN TRY
RAISERROR (N'Inserting data into #IndexColumns for clustered indexes and heaps',0,1) WITH NOWAIT;
IF @Debug = 1
BEGIN
- PRINT SUBSTRING(@dsql, 0, 4000);
- PRINT SUBSTRING(@dsql, 4000, 8000);
- PRINT SUBSTRING(@dsql, 8000, 12000);
- PRINT SUBSTRING(@dsql, 12000, 16000);
- PRINT SUBSTRING(@dsql, 16000, 20000);
- PRINT SUBSTRING(@dsql, 20000, 24000);
- PRINT SUBSTRING(@dsql, 24000, 28000);
- PRINT SUBSTRING(@dsql, 28000, 32000);
- PRINT SUBSTRING(@dsql, 32000, 36000);
- PRINT SUBSTRING(@dsql, 36000, 40000);
+ PRINT SUBSTRING(@dsql, 1, 4000);
+ PRINT SUBSTRING(@dsql, 4001, 4000);
+ PRINT SUBSTRING(@dsql, 8001, 4000);
+ PRINT SUBSTRING(@dsql, 12001, 4000);
+ PRINT SUBSTRING(@dsql, 16001, 4000);
+ PRINT SUBSTRING(@dsql, 20001, 4000);
+ PRINT SUBSTRING(@dsql, 24001, 4000);
+ PRINT SUBSTRING(@dsql, 28001, 4000);
+ PRINT SUBSTRING(@dsql, 32001, 4000);
+ PRINT SUBSTRING(@dsql, 36001, 4000);
END;
BEGIN TRY
INSERT #IndexColumns ( database_id, [schema_name], [object_id], index_id, key_ordinal, is_included_column, is_descending_key, partition_ordinal,
@@ -2591,6 +2591,7 @@ SELECT
FROM #IndexSanity;
RAISERROR (N'Populate #PartitionCompressionInfo.',0,1) WITH NOWAIT;
+IF OBJECT_ID('tempdb..#maps') IS NOT NULL DROP TABLE #maps;
WITH maps
AS
(
@@ -2605,6 +2606,7 @@ SELECT *
INTO #maps
FROM maps;
+IF OBJECT_ID('tempdb..#grps') IS NOT NULL DROP TABLE #grps;
WITH grps
AS
(
diff --git a/sp_BlitzLock.sql b/sp_BlitzLock.sql
index bb40b88c..848a324c 100644
--- a/sp_BlitzLock.sql
+++ b/sp_BlitzLock.sql
@@ -32,10 +32,11 @@ WITH RECOMPILE
AS
BEGIN
SET STATISTICS XML OFF;
- SET NOCOUNT, XACT_ABORT ON;
+ SET NOCOUNT ON;
+ SET XACT_ABORT OFF;
SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
- SELECT @Version = '8.17', @VersionDate = '20231010';
+ SELECT @Version = '8.18', @VersionDate = '20231222';
IF @VersionCheckMode = 1
BEGIN
@@ -159,6 +160,20 @@ BEGIN
THEN 1
ELSE 0
END,
+ @MI bit =
+ CASE
+ WHEN
+ (
+ SELECT
+ CONVERT
+ (
+ integer,
+ SERVERPROPERTY('EngineEdition')
+ )
+ ) = 8
+ THEN 1
+ ELSE 0
+ END,
@RDS bit =
CASE
WHEN LEFT(CAST(SERVERPROPERTY('ComputerNamePhysicalNetBIOS') AS varchar(8000)), 8) <> 'EC2AMAZ-'
@@ -297,6 +312,17 @@ BEGIN
@StartDateUTC = @StartDate,
@EndDateUTC = @EndDate;
+ IF
+ (
+ @MI = 1
+ AND @EventSessionName = N'system_health'
+ AND @TargetSessionType IS NULL
+ )
+ BEGIN
+ SET
+ @TargetSessionType = N'ring_buffer';
+ END;
+
IF @Azure = 0
BEGIN
IF NOT EXISTS
@@ -314,7 +340,7 @@ BEGIN
RETURN;
END;
END;
-
+
IF @Azure = 1
BEGIN
IF NOT EXISTS
@@ -1844,7 +1870,7 @@ BEGIN
COUNT_BIG(DISTINCT dp.event_date)
) +
N' deadlocks.',
- sort_order =
+ sort_order =
ROW_NUMBER()
OVER (ORDER BY COUNT_BIG(DISTINCT dp.event_date) DESC)
FROM #deadlock_process AS dp
@@ -1884,7 +1910,7 @@ BEGIN
SELECT
1/0
FROM sys.databases AS d
- WHERE d.name = dow.database_name
+ WHERE d.name COLLATE DATABASE_DEFAULT = dow.database_name COLLATE DATABASE_DEFAULT
AND d.is_read_committed_snapshot_on = 1
)
THEN N'You already enabled RCSI, but...'
@@ -1899,7 +1925,7 @@ BEGIN
COUNT_BIG(DISTINCT dow.event_date)
) +
N' deadlock(s) between read queries and modification queries.',
- sort_order =
+ sort_order =
ROW_NUMBER()
OVER (ORDER BY COUNT_BIG(DISTINCT dow.event_date) DESC)
FROM #deadlock_owner_waiter AS dow
@@ -1961,7 +1987,7 @@ BEGIN
COUNT_BIG(DISTINCT dow.event_date)
) +
N' deadlock(s).',
- sort_order =
+ sort_order =
ROW_NUMBER()
OVER (ORDER BY COUNT_BIG(DISTINCT dow.event_date) DESC)
FROM #deadlock_owner_waiter AS dow
@@ -2004,7 +2030,7 @@ BEGIN
COUNT_BIG(DISTINCT dow.event_date)
) +
N' deadlock(s).',
- sort_order =
+ sort_order =
ROW_NUMBER()
OVER (ORDER BY COUNT_BIG(DISTINCT dow.event_date) DESC)
FROM #deadlock_owner_waiter AS dow
@@ -2053,7 +2079,7 @@ BEGIN
COUNT_BIG(DISTINCT dow.event_date)
) +
N' deadlock(s).',
- sort_order =
+ sort_order =
ROW_NUMBER()
OVER (ORDER BY COUNT_BIG(DISTINCT dow.event_date) DESC)
FROM #deadlock_owner_waiter AS dow
@@ -2102,7 +2128,7 @@ BEGIN
COUNT_BIG(DISTINCT dp.event_date)
) +
N' instances of Serializable deadlocks.',
- sort_order =
+ sort_order =
ROW_NUMBER()
OVER (ORDER BY COUNT_BIG(DISTINCT dp.event_date) DESC)
FROM #deadlock_process AS dp
@@ -2145,7 +2171,7 @@ BEGIN
COUNT_BIG(DISTINCT dp.event_date)
) +
N' instances of Repeatable Read deadlocks.',
- sort_order =
+ sort_order =
ROW_NUMBER()
OVER (ORDER BY COUNT_BIG(DISTINCT dp.event_date) DESC)
FROM #deadlock_process AS dp
@@ -2207,7 +2233,7 @@ BEGIN
N'UNKNOWN'
) +
N'.',
- sort_order =
+ sort_order =
ROW_NUMBER()
OVER (ORDER BY COUNT_BIG(DISTINCT dp.event_date) DESC)
FROM #deadlock_process AS dp
@@ -2319,7 +2345,7 @@ BEGIN
1,
N''
) + N' locks.',
- sort_order =
+ sort_order =
ROW_NUMBER()
OVER (ORDER BY CONVERT(bigint, lt.lock_count) DESC)
FROM lock_types AS lt
@@ -2498,7 +2524,7 @@ BEGIN
COUNT_BIG(DISTINCT ds.id)
) +
N' deadlocks.',
- sort_order =
+ sort_order =
ROW_NUMBER()
OVER (ORDER BY COUNT_BIG(DISTINCT ds.id) DESC)
FROM #deadlock_stack AS ds
@@ -2599,19 +2625,19 @@ BEGIN
)
),
wait_time_hms =
- /*the more wait time you rack up the less accurate this gets,
+ /*the more wait time you rack up the less accurate this gets,
it's either that or erroring out*/
- CASE
- WHEN
+ CASE
+ WHEN
SUM
(
CONVERT
(
- bigint,
+ bigint,
dp.wait_time
)
)/1000 > 2147483647
- THEN
+ THEN
CONVERT
(
nvarchar(30),
@@ -2624,7 +2650,7 @@ BEGIN
(
CONVERT
(
- bigint,
+ bigint,
dp.wait_time
)
)
@@ -2635,16 +2661,16 @@ BEGIN
),
14
)
- WHEN
+ WHEN
SUM
(
CONVERT
(
- bigint,
+ bigint,
dp.wait_time
)
) BETWEEN 2147483648 AND 2147483647000
- THEN
+ THEN
CONVERT
(
nvarchar(30),
@@ -2657,7 +2683,7 @@ BEGIN
(
CONVERT
(
- bigint,
+ bigint,
dp.wait_time
)
)
@@ -2739,7 +2765,7 @@ BEGIN
14
) +
N' [dd hh:mm:ss:ms] of deadlock wait time.',
- sort_order =
+ sort_order =
ROW_NUMBER()
OVER (ORDER BY cs.total_waits DESC)
FROM chopsuey AS cs
@@ -2813,19 +2839,19 @@ BEGIN
)
) +
N' ' +
- /*the more wait time you rack up the less accurate this gets,
+ /*the more wait time you rack up the less accurate this gets,
it's either that or erroring out*/
- CASE
- WHEN
+ CASE
+ WHEN
SUM
(
CONVERT
(
- bigint,
+ bigint,
wt.total_wait_time_ms
)
)/1000 > 2147483647
- THEN
+ THEN
CONVERT
(
nvarchar(30),
@@ -2838,7 +2864,7 @@ BEGIN
(
CONVERT
(
- bigint,
+ bigint,
wt.total_wait_time_ms
)
)
@@ -2849,16 +2875,16 @@ BEGIN
),
14
)
- WHEN
+ WHEN
SUM
(
CONVERT
(
- bigint,
+ bigint,
wt.total_wait_time_ms
)
) BETWEEN 2147483648 AND 2147483647000
- THEN
+ THEN
CONVERT
(
nvarchar(30),
@@ -2871,7 +2897,7 @@ BEGIN
(
CONVERT
(
- bigint,
+ bigint,
wt.total_wait_time_ms
)
)
@@ -2904,7 +2930,7 @@ BEGIN
14
) END +
N' [dd hh:mm:ss:ms] of deadlock wait time.',
- sort_order =
+ sort_order =
ROW_NUMBER()
OVER (ORDER BY SUM(CONVERT(bigint, wt.total_wait_time_ms)) DESC)
FROM wait_time AS wt
@@ -2942,7 +2968,7 @@ BEGIN
N'There have been ' +
RTRIM(COUNT_BIG(DISTINCT aj.event_date)) +
N' deadlocks from this Agent Job and Step.',
- sort_order =
+ sort_order =
ROW_NUMBER()
OVER (ORDER BY COUNT_BIG(DISTINCT aj.event_date) DESC)
FROM #agent_job AS aj
@@ -3722,23 +3748,23 @@ BEGIN
BEGIN
SET @d = CONVERT(varchar(40), GETDATE(), 109);
RAISERROR('Results to client %s', 0, 1, @d) WITH NOWAIT;
-
+
IF @Debug = 1 BEGIN SET STATISTICS XML ON; END;
-
+
EXEC sys.sp_executesql
@deadlock_result;
-
+
IF @Debug = 1
BEGIN
SET STATISTICS XML OFF;
PRINT @deadlock_result;
END;
-
+
RAISERROR('Finished at %s', 0, 1, @d) WITH NOWAIT;
SET @d = CONVERT(varchar(40), GETDATE(), 109);
RAISERROR('Getting available execution plans for deadlocks %s', 0, 1, @d) WITH NOWAIT;
-
+
SELECT DISTINCT
available_plans =
'available_plans',
@@ -3774,7 +3800,7 @@ BEGIN
CONVERT(decimal(38, 6), deqs.total_worker_time / 1000. / deqs.execution_count),
total_elapsed_time_ms =
deqs.total_elapsed_time / 1000.,
- avg_elapsed_time =
+ avg_elapsed_time_ms =
CONVERT(decimal(38, 6), deqs.total_elapsed_time / 1000. / deqs.execution_count),
executions_per_second =
ISNULL
@@ -3786,7 +3812,7 @@ BEGIN
(
SECOND,
deqs.creation_time,
- deqs.last_execution_time
+ NULLIF(deqs.last_execution_time, '1900-01-01 00:00:00.000')
),
0
),
@@ -3805,7 +3831,7 @@ BEGIN
min_used_grant_mb =
deqs.min_used_grant_kb * 8. / 1024.,
max_used_grant_mb =
- deqs.max_used_grant_kb * 8. / 1024.,
+ deqs.max_used_grant_kb * 8. / 1024.,
deqs.min_reserved_threads,
deqs.max_reserved_threads,
deqs.min_used_threads,
@@ -3815,21 +3841,21 @@ BEGIN
FROM sys.dm_exec_query_stats AS deqs
WHERE EXISTS
(
- SELECT
- 1/0
- FROM #available_plans AS ap
- WHERE ap.sql_handle = deqs.sql_handle
+ SELECT
+ 1/0
+ FROM #available_plans AS ap
+ WHERE ap.sql_handle = deqs.sql_handle
)
AND deqs.query_hash IS NOT NULL;
-
- CREATE CLUSTERED INDEX
- deqs
+
+ CREATE CLUSTERED INDEX
+ deqs
ON #dm_exec_query_stats
(
- sql_handle,
+ sql_handle,
plan_handle
);
-
+
SELECT
ap.available_plans,
ap.database_name,
@@ -3843,7 +3869,7 @@ BEGIN
ap.total_worker_time_ms,
ap.avg_worker_time_ms,
ap.total_elapsed_time_ms,
- ap.avg_elapsed_time,
+ ap.avg_elapsed_time_ms,
ap.total_logical_reads_mb,
ap.total_physical_reads_mb,
ap.total_logical_writes_mb,
@@ -3861,7 +3887,7 @@ BEGIN
ap.statement_end_offset
FROM
(
-
+
SELECT
ap.*,
c.statement_start_offset,
@@ -3872,7 +3898,7 @@ BEGIN
c.total_worker_time_ms,
c.avg_worker_time_ms,
c.total_elapsed_time_ms,
- c.avg_elapsed_time,
+ c.avg_elapsed_time_ms,
c.executions_per_second,
c.total_physical_reads_mb,
c.total_logical_writes_mb,
@@ -3911,10 +3937,10 @@ BEGIN
OPTION(RECOMPILE, LOOP JOIN, HASH JOIN);
RAISERROR('Finished at %s', 0, 1, @d) WITH NOWAIT;
-
+
SET @d = CONVERT(varchar(40), GETDATE(), 109);
RAISERROR('Returning findings %s', 0, 1, @d) WITH NOWAIT;
-
+
SELECT
df.check_id,
df.database_name,
@@ -3926,7 +3952,7 @@ BEGIN
df.check_id,
df.sort_order
OPTION(RECOMPILE);
-
+
SET @d = CONVERT(varchar(40), GETDATE(), 109);
RAISERROR('Finished at %s', 0, 1, @d) WITH NOWAIT;
END; /*done with output to client app.*/
diff --git a/sp_BlitzQueryStore.sql b/sp_BlitzQueryStore.sql
index 6ff69f24..084e988f 100644
--- a/sp_BlitzQueryStore.sql
+++ b/sp_BlitzQueryStore.sql
@@ -57,7 +57,7 @@ SET NOCOUNT ON;
SET STATISTICS XML OFF;
SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
-SELECT @Version = '8.17', @VersionDate = '20231010';
+SELECT @Version = '8.18', @VersionDate = '20231222';
IF(@VersionCheckMode = 1)
BEGIN
RETURN;
@@ -118,8 +118,6 @@ IF (SELECT CONVERT(NVARCHAR(128), SERVERPROPERTY ('EDITION'))) <> 'SQL Azure'
IF @Help = 1
BEGIN
-
- SELECT N'You have requested assistance. It will arrive as soon as humanly possible.' AS [Take four red capsules, help is on the way];
PRINT N'
sp_BlitzQueryStore from http://FirstResponderKit.org
@@ -163,6 +161,257 @@ IF @Help = 1
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
';
+ /*Parameter info*/
+ SELECT N'@Help' AS [Parameter Name] ,
+ N'BIT' AS [Data Type] ,
+ N'0' AS [Default Value],
+ N'Displays this help message.' AS [Parameter Description]
+ UNION ALL
+ SELECT N'@DatabaseName',
+ N'NVARCHAR(128)',
+ N'NULL',
+ N'The name of the database you want to check the query store for.'
+ UNION ALL
+ SELECT N'@Top',
+ N'INT',
+ N'3',
+ N'The number of records to retrieve and analyze from the query store. The following system views are used: query_store_query, query_context_settings, query_store_wait_stats, query_store_runtime_stats,query_store_plan.'
+
+ UNION ALL
+ SELECT N'@StartDate',
+ N'DATETIME2(7)',
+ N'NULL',
+ N'Get query store info starting from this date. When not specified, sp_BlitzQueryStore gets info from the last 7 days'
+ UNION ALL
+ SELECT N'@EndDate',
+ N'DATETIME2(7)',
+ N'NULL',
+ N'Get query store info until this date. When not specified, sp_BlitzQueryStore gets info from the last 7 days'
+ UNION ALL
+ SELECT N'@MinimumExecutionCount',
+ N'INT',
+ N'NULL',
+ N'When a value is specified, sp_BlitzQueryStore gets info for queries where count_executions >= @MinimumExecutionCount'
+ UNION ALL
+ SELECT N'@DurationFilter',
+ N'DECIMAL(38,4)',
+ N'NULL',
+ N'Time unit - seconds. When a value is specified, sp_BlitzQueryStore gets info for queries where the average duration >= @DurationFilter'
+ UNION ALL
+ SELECT N'@StoredProcName',
+ N'NVARCHAR(128)',
+ N'NULL',
+ N'Get information for this specific stored procedure.'
+ UNION ALL
+ SELECT N'@Failed',
+ N'BIT',
+ N'0',
+ N'When set to 1, only information about failed queries is returned.'
+ UNION ALL
+ SELECT N'@PlanIdFilter',
+ N'INT',
+ N'NULL',
+ N'The ID of the plan you want to check for.'
+ UNION ALL
+ SELECT N'@QueryIdFilter',
+ N'INT',
+ N'NULL',
+ N'The ID of the query you want to check for.'
+ UNION ALL
+ SELECT N'@ExportToExcel',
+ N'BIT',
+ N'0',
+ N'When set to 1, prepares 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'@HideSummary',
+ N'BIT',
+ N'0',
+ N'When set to 1, hides the findings summary result set.'
+ UNION ALL
+ SELECT N'@SkipXML',
+ N'BIT',
+ N'0',
+ N'When set to 1, missing_indexes, implicit_conversion_info, cached_execution_parameters, are not returned. Does not affect query_plan_xml'
+ UNION ALL
+ SELECT N'@Debug',
+ N'BIT',
+ N'0',
+ N'Setting this to 1 will print dynamic SQL and select data from all tables used.'
+ UNION ALL
+ SELECT N'@ExpertMode',
+ N'BIT',
+ N'0',
+ N'When set to 1, more checks are done. Examples: many to many merge joins, row goals, adaptive joins, stats info, bad scans and plan forcing, computed columns that reference scalar UDFs.'
+ UNION ALL
+ SELECT N'@VersionCheckMode',
+ N'BIT',
+ N'0',
+ N'Outputs the version number and date.'
+
+ /* Column definitions */
+ SELECT 'database_name' AS [Column Name],
+ 'NVARCHAR(258)' AS [Data Type],
+ 'The name of the database where the plan was encountered.' AS [Column Description]
+ UNION ALL
+ SELECT 'query_cost',
+ 'FLOAT',
+ 'The cost of the execution plan in query bucks.'
+ UNION ALL
+ SELECT 'plan_id',
+ 'BIGINT',
+ 'The ID of the plan from sys.query_store_plan.'
+ UNION ALL
+ SELECT 'query_id',
+ 'BIGINT',
+ 'The ID of the query from sys.query_store_query.'
+ UNION ALL
+ SELECT 'query_id_all_plan_ids',
+ 'VARCHAR(8000)',
+ 'Comma-separated list of all query plan IDs associated with this query.'
+ UNION ALL
+ SELECT 'query_sql_text',
+ 'NVARCHAR(MAX)',
+ 'The text of the query, as provided by the user/app. Includes whitespaces, hints and comments. Comments and spaces before and after the query text are ignored.'
+ UNION ALL
+ SELECT 'proc_or_function_name',
+ 'NVARCHAR(258)',
+ 'If the query is part of a function/stored procedure, you''ll see here the name of its parent object.'
+ UNION ALL
+ SELECT 'query_plan_xml',
+ ' XML',
+ 'The query plan. Click to display a graphical plan.'
+ UNION ALL
+ SELECT 'warnings',
+ 'VARCHAR(MAX)',
+ 'A list of individual warnings generated by this query.'
+ UNION ALL
+ SELECT 'pattern',
+ 'NVARCHAR(512)',
+ 'A list of performance related patterns identified for this query.'
+ UNION ALL
+ SELECT 'parameter_sniffing_symptoms',
+ 'NVARCHAR(4000)',
+ 'A list of all the identified symptoms that are usually indicators of parameter sniffing.'
+ UNION ALL
+ SELECT 'last_force_failure_reason_desc',
+ 'NVARCHAR(258)',
+ 'Reason why plan forcing failed. NONE if plan isn''t forced.'
+ UNION ALL
+ SELECT 'top_three_waits',
+ 'NVARCHAR(MAX)',
+ 'The top 3 wait types, and their times in milliseconds, recorded for this query.'
+ UNION ALL
+ SELECT 'missing_indexes',
+ 'XML',
+ 'Missing index recommendations retrieved from the query plan.'
+ UNION ALL
+ SELECT 'implicit_conversion_info',
+ 'XML',
+ 'Information about the implicit conversion warnings,if any, retrieved from the query plan.'
+ UNION ALL
+ SELECT 'cached_execution_parameters',
+ 'XML',
+ 'Names, data types, and values for the parameters used when the query plan was compiled.'
+ UNION ALL
+ SELECT 'count_executions ',
+ 'BIGINT',
+ 'The number of executions of this particular query.'
+ UNION ALL
+ SELECT 'count_compiles',
+ 'BIGINT',
+ 'The number of plan compilations for this particular query.'
+ UNION ALL
+ SELECT 'total_cpu_time',
+ 'BIGINT',
+ 'Total CPU time, reported in milliseconds, that was consumed by all executions of this query.'
+ UNION ALL
+ SELECT 'avg_cpu_time ',
+ 'BIGINT',
+ 'Average CPU time, reported in milliseconds, consumed by each execution of this query.'
+ UNION ALL
+ SELECT 'total_duration',
+ 'BIGINT',
+ 'Total elapsed time, reported in milliseconds, consumed by all executions of this query.'
+ UNION ALL
+ SELECT 'avg_duration',
+ 'BIGINT',
+ 'Average elapsed time, reported in milliseconds, consumed by each execution of this query.'
+ UNION ALL
+ SELECT 'total_logical_io_reads',
+ 'BIGINT',
+ 'Total logical reads, reported in MB, performed by this query.'
+ UNION ALL
+ SELECT 'avg_logical_io_reads',
+ 'BIGINT',
+ 'Average logical reads, reported in MB, performed by each execution of this query.'
+ UNION ALL
+ SELECT 'total_physical_io_reads',
+ 'BIGINT',
+ 'Total physical reads, reported in MB, performed by this query.'
+ UNION ALL
+ SELECT 'avg_physical_io_reads',
+ 'BIGINT',
+ 'Average physical reads, reported in MB, performed by each execution of this query.'
+ UNION ALL
+ SELECT 'total_logical_io_writes',
+ 'BIGINT',
+ 'Total logical writes, reported in MB, performed by this query.'
+ UNION ALL
+ SELECT 'avg_logical_io_writes',
+ 'BIGINT',
+ 'Average logical writes, reported in MB, performed by each execution of this query.'
+ UNION ALL
+ SELECT 'total_rowcount',
+ 'BIGINT',
+ 'Total number of rows returned for all executions of this query.'
+ UNION ALL
+ SELECT 'avg_rowcount',
+ 'BIGINT',
+ 'Average number of rows returned by each execution of this query.'
+ UNION ALL
+ SELECT 'total_query_max_used_memory',
+ 'DECIMAL(38,2)',
+ 'Total max memory grant, reported in MB, used by this query.'
+ UNION ALL
+ SELECT 'avg_query_max_used_memory',
+ 'DECIMAL(38,2)',
+ 'Average max memory grant, reported in MB, used by each execution of this query.'
+ UNION ALL
+ SELECT 'total_tempdb_space_used',
+ 'DECIMAL(38,2)',
+ 'Total tempdb space, reported in MB, used by this query.'
+ UNION ALL
+ SELECT 'avg_tempdb_space_used',
+ 'DECIMAL(38,2)',
+ 'Average tempdb space, reported in MB, used by each execution of this query.'
+ UNION ALL
+ SELECT 'total_log_bytes_used',
+ 'DECIMAL(38,2)',
+ 'Total number of bytes in the database log used by this query.'
+ UNION ALL
+ SELECT 'avg_log_bytes_used',
+ 'DECIMAL(38,2)',
+ 'Average number of bytes in the database log used by each execution of this query.'
+ UNION ALL
+ SELECT 'total_num_physical_io_reads',
+ 'DECIMAL(38,2)',
+ 'Total number of physical I/O reads performed by this query (expressed as a number of read I/O operations).'
+ UNION ALL
+ SELECT 'avg_num_physical_io_reads',
+ 'DECIMAL(38,2)',
+ 'Average number of physical I/O reads performed by each execution of this query (expressed as a number of read I/O operations).'
+ UNION ALL
+ SELECT 'first_execution_time',
+ 'DATETIME2',
+ 'First execution time for this query within the aggregation interval. This is the end time of the query execution.'
+ UNION ALL
+ SELECT 'last_execution_time',
+ 'DATETIME2',
+ 'Last execution time for this query within the aggregation interval. This is the end time of the query execution.'
+ UNION ALL
+ SELECT 'context_settings',
+ 'NVARCHAR(512)',
+ 'Contains information about context settings associated with this query.';
RETURN;
END;
diff --git a/sp_BlitzWho.sql b/sp_BlitzWho.sql
index d3e9f100..d623706c 100644
--- a/sp_BlitzWho.sql
+++ b/sp_BlitzWho.sql
@@ -33,7 +33,7 @@ BEGIN
SET STATISTICS XML OFF;
SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
- SELECT @Version = '8.17', @VersionDate = '20231010';
+ SELECT @Version = '8.18', @VersionDate = '20231222';
IF(@VersionCheckMode = 1)
BEGIN
diff --git a/sp_DatabaseRestore.sql b/sp_DatabaseRestore.sql
index d71b1a3e..71fef935 100755
--- a/sp_DatabaseRestore.sql
+++ b/sp_DatabaseRestore.sql
@@ -45,7 +45,7 @@ SET STATISTICS XML OFF;
/*Versioning details*/
-SELECT @Version = '8.17', @VersionDate = '20231010';
+SELECT @Version = '8.18', @VersionDate = '20231222';
IF(@VersionCheckMode = 1)
BEGIN
diff --git a/sp_ineachdb.sql b/sp_ineachdb.sql
index c7bddb69..9cf874ba 100644
--- a/sp_ineachdb.sql
+++ b/sp_ineachdb.sql
@@ -4,38 +4,39 @@ GO
ALTER PROCEDURE [dbo].[sp_ineachdb]
-- mssqltips.com/sqlservertip/5694/execute-a-command-in-the-context-of-each-database-in-sql-server--part-2/
- @command nvarchar(max) = NULL,
- @replace_character nchar(1) = N'?',
- @print_dbname bit = 0,
- @select_dbname bit = 0,
- @print_command bit = 0,
- @print_command_only bit = 0,
- @suppress_quotename bit = 0, -- use with caution
- @system_only bit = 0,
- @user_only bit = 0,
- @name_pattern nvarchar(300) = N'%',
- @database_list nvarchar(max) = NULL,
- @exclude_pattern nvarchar(300) = NULL,
- @exclude_list nvarchar(max) = NULL,
- @recovery_model_desc nvarchar(120) = NULL,
- @compatibility_level tinyint = NULL,
- @state_desc nvarchar(120) = N'ONLINE',
- @is_read_only bit = 0,
- @is_auto_close_on bit = NULL,
- @is_auto_shrink_on bit = NULL,
- @is_broker_enabled bit = NULL,
- @user_access nvarchar(128) = NULL,
- @Help BIT = 0,
- @Version VARCHAR(30) = NULL OUTPUT,
- @VersionDate DATETIME = NULL OUTPUT,
- @VersionCheckMode BIT = 0
+ @command nvarchar(max) = NULL,
+ @replace_character nchar(1) = N'?',
+ @print_dbname bit = 0,
+ @select_dbname bit = 0,
+ @print_command bit = 0,
+ @print_command_only bit = 0,
+ @suppress_quotename bit = 0, -- use with caution
+ @system_only bit = 0,
+ @user_only bit = 0,
+ @name_pattern nvarchar(300) = N'%',
+ @database_list nvarchar(max) = NULL,
+ @exclude_pattern nvarchar(300) = NULL,
+ @exclude_list nvarchar(max) = NULL,
+ @recovery_model_desc nvarchar(120) = NULL,
+ @compatibility_level tinyint = NULL,
+ @state_desc nvarchar(120) = N'ONLINE',
+ @is_read_only bit = 0,
+ @is_auto_close_on bit = NULL,
+ @is_auto_shrink_on bit = NULL,
+ @is_broker_enabled bit = NULL,
+ @user_access nvarchar(128) = NULL,
+ @Help bit = 0,
+ @Version varchar(30) = NULL OUTPUT,
+ @VersionDate datetime = NULL OUTPUT,
+ @VersionCheckMode bit = 0,
+ @is_ag_writeable_copy bit = 0
-- WITH EXECUTE AS OWNER – maybe not a great idea, depending on the security of your system
AS
BEGIN
SET NOCOUNT ON;
SET STATISTICS XML OFF;
- SELECT @Version = '8.17', @VersionDate = '20231010';
+ SELECT @Version = '8.18', @VersionDate = '20231222';
IF(@VersionCheckMode = 1)
BEGIN
@@ -277,6 +278,22 @@ OPTION (MAXRECURSION 0);
AND ar.secondary_role_allow_connections = 0
AND ags.primary_replica <> @ServerName
);
+ /* Remove databases which are not the writeable copies in an AG. */
+ IF @is_ag_writeable_copy = 1
+ BEGIN
+ DELETE dbs FROM #ineachdb AS dbs
+ WHERE EXISTS
+ (
+ SELECT 1 FROM sys.dm_hadr_database_replica_states AS drs
+ INNER JOIN sys.availability_replicas AS ar
+ ON ar.replica_id = drs.replica_id
+ INNER JOIN sys.dm_hadr_availability_group_states AS ags
+ ON ags.group_id = ar.group_id
+ WHERE drs.database_id = dbs.id
+ AND drs.is_primary_replica <> 1
+ AND ags.primary_replica <> @ServerName
+ );
+ END
END
-- Well, if we deleted them all...