Skip to content

Commit 0364c73

Browse files
sp_BlitzWho: Fix bugs found in full code review
Bug fixes: - AND/OR precedence in >50GB memory check: The AND 50000000 < (...) condition only bound to the last OR branch (@ProductVersionMajor >= 13) due to operator precedence. SQL Server 2012 SP3+ and 2014 SP2+ always got MAX_GRANT_PERCENT = 1 regardless of server memory. Wrapped the version OR chain in parentheses so the memory check applies to all supported versions. - AND/OR precedence in @ShowSleepingSPIDs=1: The bare OR clause short-circuited all preceding AND conditions (@@spid exclusion, host_name IS NOT NULL, AG read-only replica exclusion). Any session with an open transaction was returned unfiltered. Changed to AND (db_name IS NOT NULL OR open_tran >= 1) so base filters always apply. - NOT IN with NULL r.database_id on AG servers: When r is NULL (sleeping sessions with no active request), NULL NOT IN (set) evaluates to UNKNOWN, silently excluding all sleeping sessions on servers with Always On read-only replicas. Added r.database_id IS NULL OR guard. - Session waits TOP 5 ordered alphabetically: The @SessionWaitsSQL subquery used ORDER BY 1 which sorts by the concatenated string (alphabetically), not by wait time. Changed to ORDER BY SUM(waitwait.wait_time_ms) DESC to return the 5 longest waits, matching the dm_os_waiting_tasks subquery pattern. Code quality: - Removed unused variable @StringToSelect (declared but never referenced). - Removed 4 redundant @ObjectFullName assignments (same value set 5 consecutive times with no changes to inputs between them). Tested: 12 execution scenarios on SQL2022 including default, Help, ExpertMode, ShowSleepingSPIDs (0/1/2), Debug, MinElapsedSeconds filter, SortOrder, GetOuterCommand, GetLiveQueryPlan, and ShowActualParameters. All passed. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
1 parent 2422c4b commit 0364c73

1 file changed

Lines changed: 10 additions & 14 deletions

File tree

‎sp_BlitzWho.sql‎

Lines changed: 10 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -93,7 +93,6 @@ DECLARE @ProductVersion NVARCHAR(128) = CAST(SERVERPROPERTY('ProductVersion') A
9393
,@AzureSQLDB BIT = (SELECT CASE WHEN SERVERPROPERTY('EngineEdition') = 5 THEN 1 ELSE 0 END)
9494
,@EnhanceFlag BIT = 0
9595
,@BlockingCheck NVARCHAR(MAX)
96-
,@StringToSelect NVARCHAR(MAX)
9796
,@StringToExecute NVARCHAR(MAX)
9897
,@OutputTableCleanupDate DATE
9998
,@SessionWaits BIT = 0
@@ -107,7 +106,7 @@ DECLARE @ProductVersion NVARCHAR(128) = CAST(SERVERPROPERTY('ProductVersion') A
107106
WHERE waitwait.session_id = wait.session_id
108107
GROUP BY waitwait.wait_type
109108
HAVING SUM(waitwait.wait_time_ms) > 5
110-
ORDER BY 1
109+
ORDER BY SUM(waitwait.wait_time_ms) DESC
111110
FOR
112111
XML PATH('''') ) AS session_wait_info
113112
FROM sys.dm_exec_session_wait_stats AS wait ) AS wt2
@@ -291,28 +290,24 @@ IF @OutputDatabaseName IS NOT NULL AND @OutputSchemaName IS NOT NULL AND @Output
291290
EXEC(@StringToExecute);
292291

293292
/* If the table doesn't have the new cached_parameter_info computed column, add it. See Github #2842. */
294-
SET @ObjectFullName = @OutputDatabaseName + N'.' + @OutputSchemaName + N'.' + @OutputTableName;
295293
SET @StringToExecute = N'IF NOT EXISTS (SELECT * FROM ' + @OutputDatabaseName + N'.sys.all_columns
296294
WHERE object_id = (OBJECT_ID(''' + @ObjectFullName + N''')) AND name = ''cached_parameter_info'')
297295
ALTER TABLE ' + @ObjectFullName + N' ADD cached_parameter_info NVARCHAR(MAX) NULL;';
298296
EXEC(@StringToExecute);
299297

300298
/* If the table doesn't have the new live_parameter_info computed column, add it. See Github #2842. */
301-
SET @ObjectFullName = @OutputDatabaseName + N'.' + @OutputSchemaName + N'.' + @OutputTableName;
302299
SET @StringToExecute = N'IF NOT EXISTS (SELECT * FROM ' + @OutputDatabaseName + N'.sys.all_columns
303300
WHERE object_id = (OBJECT_ID(''' + @ObjectFullName + N''')) AND name = ''live_parameter_info'')
304301
ALTER TABLE ' + @ObjectFullName + N' ADD live_parameter_info NVARCHAR(MAX) NULL;';
305302
EXEC(@StringToExecute);
306303

307304
/* If the table doesn't have the new outer_command column, add it. See Github #2887. */
308-
SET @ObjectFullName = @OutputDatabaseName + N'.' + @OutputSchemaName + N'.' + @OutputTableName;
309305
SET @StringToExecute = N'IF NOT EXISTS (SELECT * FROM ' + @OutputDatabaseName + N'.sys.all_columns
310306
WHERE object_id = (OBJECT_ID(''' + @ObjectFullName + N''')) AND name = ''outer_command'')
311307
ALTER TABLE ' + @ObjectFullName + N' ADD outer_command NVARCHAR(4000) NULL;';
312308
EXEC(@StringToExecute);
313309

314310
/* If the table doesn't have the new wait_resource column, add it. See Github #2970. */
315-
SET @ObjectFullName = @OutputDatabaseName + N'.' + @OutputSchemaName + N'.' + @OutputTableName;
316311
SET @StringToExecute = N'IF NOT EXISTS (SELECT * FROM ' + @OutputDatabaseName + N'.sys.all_columns
317312
WHERE object_id = (OBJECT_ID(''' + @ObjectFullName + N''')) AND name = ''wait_resource'')
318313
ALTER TABLE ' + @ObjectFullName + N' ADD wait_resource NVARCHAR(MAX) NULL;';
@@ -894,7 +889,7 @@ BEGIN
894889
+ CASE WHEN @ShowSleepingSPIDs = 0 THEN
895890
N' AND COALESCE(DB_NAME(r.database_id), DB_NAME(blocked.dbid)) IS NOT NULL'
896891
WHEN @ShowSleepingSPIDs = 1 THEN
897-
N' OR COALESCE(r.open_transaction_count, blocked.open_tran) >= 1'
892+
N' AND (COALESCE(DB_NAME(r.database_id), DB_NAME(blocked.dbid)) IS NOT NULL OR COALESCE(r.open_transaction_count, blocked.open_tran) >= 1)'
898893
ELSE N'' END;
899894
END /* IF @ProductVersionMajor > 9 and @ProductVersionMajor < 11 */
900895

@@ -1195,12 +1190,12 @@ IF @ProductVersionMajor >= 11
11951190
11961191
WHERE s.session_id <> @@SPID
11971192
AND s.host_name IS NOT NULL
1198-
AND r.database_id NOT IN (SELECT database_id FROM #WhoReadableDBs)
1193+
AND (r.database_id IS NULL OR r.database_id NOT IN (SELECT database_id FROM #WhoReadableDBs))
11991194
'
12001195
+ CASE WHEN @ShowSleepingSPIDs = 0 THEN
12011196
N' AND COALESCE(DB_NAME(r.database_id), DB_NAME(blocked.dbid)) IS NOT NULL'
12021197
WHEN @ShowSleepingSPIDs = 1 THEN
1203-
N' OR COALESCE(r.open_transaction_count, blocked.open_tran) >= 1'
1198+
N' AND (COALESCE(DB_NAME(r.database_id), DB_NAME(blocked.dbid)) IS NOT NULL OR COALESCE(r.open_transaction_count, blocked.open_tran) >= 1)'
12041199
ELSE N'' END;
12051200

12061201

@@ -1378,11 +1373,12 @@ ELSE
13781373
SET @StringToExecute = @BlockingCheck + N' SELECT GETDATE() AS run_date , ' + @StringToExecute;
13791374

13801375
/* If the server has > 50GB of memory, add a max grant hint to avoid getting a giant grant */
1381-
IF (@ProductVersionMajor = 11 AND @ProductVersionMinor >= 6020)
1382-
OR (@ProductVersionMajor = 12 AND @ProductVersionMinor >= 5000 )
1383-
OR (@ProductVersionMajor >= 13 )
1384-
AND 50000000 < (SELECT cntr_value
1385-
FROM sys.dm_os_performance_counters
1376+
IF ( (@ProductVersionMajor = 11 AND @ProductVersionMinor >= 6020)
1377+
OR (@ProductVersionMajor = 12 AND @ProductVersionMinor >= 5000 )
1378+
OR (@ProductVersionMajor >= 13 )
1379+
)
1380+
AND 50000000 < (SELECT cntr_value
1381+
FROM sys.dm_os_performance_counters
13861382
WHERE object_name LIKE '%:Memory Manager%'
13871383
AND counter_name LIKE 'Target Server Memory (KB)%')
13881384
BEGIN

0 commit comments

Comments
 (0)