Skip to content

Commit fab85e7

Browse files
BrentOzarclaude
andcommitted
sp_kill: rename temp table to #hitlist, fix AND filter logic
Rename #sp_kill_sessions to #hitlist. Replace sequential subtractive filter logic (mark all, then un-mark per filter) with a single UPDATE that combines all filters as AND conditions. This ensures that passing multiple filters like @loginname + @appName only kills sessions matching both, not sessions matching either. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
1 parent befc0d3 commit fab85e7

1 file changed

Lines changed: 50 additions & 141 deletions

File tree

sp_kill.sql

Lines changed: 50 additions & 141 deletions
Original file line numberDiff line numberDiff line change
@@ -282,7 +282,7 @@ For more info, visit http://FirstResponderKit.org
282282
/*-------------------------------------------------------
283283
Section 5: Temp Table Creation
284284
-------------------------------------------------------*/
285-
CREATE TABLE #sp_kill_sessions (
285+
CREATE TABLE #hitlist (
286286
Id INT IDENTITY(1,1) NOT NULL PRIMARY KEY CLUSTERED,
287287
ServerName NVARCHAR(128) NULL,
288288
CheckDate DATETIMEOFFSET NULL,
@@ -335,7 +335,7 @@ For more info, visit http://FirstResponderKit.org
335335
RAISERROR('Collecting session data from DMVs...', 0, 1) WITH NOWAIT;
336336

337337
SET @StringToExecute = CAST(N'' AS NVARCHAR(MAX)) + N'
338-
INSERT INTO #sp_kill_sessions (
338+
INSERT INTO #hitlist (
339339
ServerName, CheckDate, CallerLoginName, CallerHostName, ParametersUsed,
340340
KillCommand, session_id, [status], blocking_session_id,
341341
wait_type, wait_time_ms, wait_resource,
@@ -463,149 +463,38 @@ For more info, visit http://FirstResponderKit.org
463463
RAISERROR('Applying kill recommendation logic...', 0, 1) WITH NOWAIT;
464464

465465
/* 7a: Mark rollbacks as not killable */
466-
UPDATE #sp_kill_sessions
466+
UPDATE #hitlist
467467
SET KillRecommended = 0,
468468
Reason = N'Session is rolling back - not safe to kill.'
469469
WHERE [status] = 'rollback';
470470

471471
/* 7b: If @SPID is specified, only recommend that one */
472472
IF @SPID IS NOT NULL
473473
BEGIN
474-
IF NOT EXISTS (SELECT 1 FROM #sp_kill_sessions WHERE session_id = @SPID)
474+
IF NOT EXISTS (SELECT 1 FROM #hitlist WHERE session_id = @SPID)
475475
BEGIN
476476
RAISERROR('The specified @SPID %d was not found among active user sessions.', 11, 1, @SPID) WITH NOWAIT;
477477
/* Still return results so user can see what IS running */
478478
END
479-
ELSE IF EXISTS (SELECT 1 FROM #sp_kill_sessions WHERE session_id = @SPID AND [status] = 'rollback')
479+
ELSE IF EXISTS (SELECT 1 FROM #hitlist WHERE session_id = @SPID AND [status] = 'rollback')
480480
BEGIN
481481
RAISERROR('The specified @SPID %d is currently rolling back and cannot be killed.', 11, 1, @SPID) WITH NOWAIT;
482482
END
483483
ELSE
484484
BEGIN
485-
UPDATE #sp_kill_sessions
485+
UPDATE #hitlist
486486
SET KillRecommended = 1,
487487
Reason = N'Targeted by @SPID parameter.'
488488
WHERE session_id = @SPID
489489
AND [status] <> 'rollback';
490490
END;
491491
END
492-
/* 7c: Otherwise, apply filters */
492+
/* 7c: Otherwise, apply all filters as AND conditions in a single pass.
493+
A session must match ALL specified filters to be recommended for kill.
494+
If @ExecuteKills = 'N' and no filters are set, don't recommend anything. */
493495
ELSE
494496
BEGIN
495-
/* Start by recommending all non-rollback sessions */
496-
UPDATE #sp_kill_sessions
497-
SET KillRecommended = 1
498-
WHERE [status] <> 'rollback';
499-
500-
/* Apply each filter to narrow down */
501-
IF @LoginName IS NOT NULL
502-
BEGIN
503-
UPDATE #sp_kill_sessions
504-
SET KillRecommended = 0,
505-
Reason = ISNULL(Reason + N' ', N'') + N'Does not match @LoginName filter.'
506-
WHERE KillRecommended = 1
507-
AND login_name <> @LoginName;
508-
END;
509-
510-
IF @AppName IS NOT NULL
511-
BEGIN
512-
UPDATE #sp_kill_sessions
513-
SET KillRecommended = 0,
514-
Reason = ISNULL(Reason + N' ', N'') + N'Does not match @AppName filter.'
515-
WHERE KillRecommended = 1
516-
AND program_name NOT LIKE @AppName;
517-
END;
518-
519-
IF @DatabaseName IS NOT NULL
520-
BEGIN
521-
UPDATE #sp_kill_sessions
522-
SET KillRecommended = 0,
523-
Reason = ISNULL(Reason + N' ', N'') + N'Does not match @DatabaseName filter.'
524-
WHERE KillRecommended = 1
525-
AND database_name <> @DatabaseName;
526-
END;
527-
528-
IF @HostName IS NOT NULL
529-
BEGIN
530-
UPDATE #sp_kill_sessions
531-
SET KillRecommended = 0,
532-
Reason = ISNULL(Reason + N' ', N'') + N'Does not match @HostName filter.'
533-
WHERE KillRecommended = 1
534-
AND host_name <> @HostName;
535-
END;
536-
537-
IF @LeadBlockers = 'Y'
538-
BEGIN
539-
/* A lead blocker blocks at least one other session and is not itself blocked */
540-
UPDATE #sp_kill_sessions
541-
SET KillRecommended = 0,
542-
Reason = ISNULL(Reason + N' ', N'') + N'Not a lead blocker.'
543-
WHERE KillRecommended = 1
544-
AND NOT (
545-
/* This session is blocking someone */
546-
EXISTS (SELECT 1 FROM #sp_kill_sessions blocked WHERE blocked.blocking_session_id = #sp_kill_sessions.session_id)
547-
/* And this session is not itself blocked */
548-
AND (blocking_session_id IS NULL OR blocking_session_id = 0)
549-
);
550-
END;
551-
552-
IF @ReadOnly = 'Y'
553-
BEGIN
554-
UPDATE #sp_kill_sessions
555-
SET KillRecommended = 0,
556-
Reason = ISNULL(Reason + N' ', N'') + N'Not a read-only query.'
557-
WHERE KillRecommended = 1
558-
AND is_read_only = 0;
559-
END;
560-
561-
IF @SPIDState = 'S'
562-
BEGIN
563-
UPDATE #sp_kill_sessions
564-
SET KillRecommended = 0,
565-
Reason = ISNULL(Reason + N' ', N'') + N'Not sleeping (@SPIDState = S).'
566-
WHERE KillRecommended = 1
567-
AND [status] <> 'sleeping';
568-
END;
569-
570-
IF @SPIDState = 'R'
571-
BEGIN
572-
UPDATE #sp_kill_sessions
573-
SET KillRecommended = 0,
574-
Reason = ISNULL(Reason + N' ', N'') + N'Not running (@SPIDState = R).'
575-
WHERE KillRecommended = 1
576-
AND [status] <> 'running';
577-
END;
578-
579-
IF @HasOpenTran = 'Y'
580-
BEGIN
581-
UPDATE #sp_kill_sessions
582-
SET KillRecommended = 0,
583-
Reason = ISNULL(Reason + N' ', N'') + N'No open transactions.'
584-
WHERE KillRecommended = 1
585-
AND ISNULL(open_transaction_count, 0) = 0;
586-
END;
587-
588-
IF @RequestsOlderThanMinutes IS NOT NULL
589-
BEGIN
590-
UPDATE #sp_kill_sessions
591-
SET KillRecommended = 0,
592-
Reason = ISNULL(Reason + N' ', N'') + N'Request not old enough for @RequestsOlderThanMinutes filter.'
593-
WHERE KillRecommended = 1
594-
AND last_request_start_time > DATEADD(MINUTE, -@RequestsOlderThanMinutes, GETDATE());
595-
END;
596-
597-
IF @OmitLogin <> ''
598-
BEGIN
599-
UPDATE #sp_kill_sessions
600-
SET KillRecommended = 0,
601-
Reason = ISNULL(Reason + N' ', N'') + N'Login excluded by @OmitLogin.'
602-
WHERE KillRecommended = 1
603-
AND login_name = @OmitLogin;
604-
END;
605-
606-
/* If no targeting filters were set and @ExecuteKills = 'N', don't recommend
607-
killing anything - just show all sessions. When @ExecuteKills = 'Y',
608-
no filters means kill everything (except our own session). */
497+
/* When in display mode with no filters, just show sessions without recommending kills */
609498
IF @ExecuteKills = 'N'
610499
AND @LoginName IS NULL
611500
AND @AppName IS NULL
@@ -618,10 +507,30 @@ For more info, visit http://FirstResponderKit.org
618507
AND @RequestsOlderThanMinutes IS NULL
619508
AND @OmitLogin = ''
620509
BEGIN
621-
UPDATE #sp_kill_sessions
622-
SET KillRecommended = 0,
623-
Reason = NULL
624-
WHERE KillRecommended = 1;
510+
/* No filters in display mode - nothing to recommend */
511+
IF @Debug = 1
512+
RAISERROR('No filters specified in display mode - showing all sessions without recommendations.', 0, 1) WITH NOWAIT;
513+
END
514+
ELSE
515+
BEGIN
516+
/* Recommend sessions that match ALL specified filters */
517+
UPDATE h
518+
SET KillRecommended = 1
519+
FROM #hitlist h
520+
WHERE [status] <> 'rollback'
521+
AND (@LoginName IS NULL OR login_name = @LoginName)
522+
AND (@AppName IS NULL OR program_name LIKE @AppName)
523+
AND (@DatabaseName IS NULL OR database_name = @DatabaseName)
524+
AND (@HostName IS NULL OR host_name = @HostName)
525+
AND (@ReadOnly = 'N' OR is_read_only = 1)
526+
AND (@SPIDState = '' OR (@SPIDState = 'S' AND [status] = 'sleeping') OR (@SPIDState = 'R' AND [status] = 'running'))
527+
AND (@HasOpenTran = '' OR ISNULL(open_transaction_count, 0) > 0)
528+
AND (@RequestsOlderThanMinutes IS NULL OR last_request_start_time <= DATEADD(MINUTE, -@RequestsOlderThanMinutes, GETDATE()))
529+
AND (@OmitLogin = '' OR login_name <> @OmitLogin)
530+
AND (@LeadBlockers = 'N' OR (
531+
EXISTS (SELECT 1 FROM #hitlist blocked WHERE blocked.blocking_session_id = h.session_id)
532+
AND (h.blocking_session_id IS NULL OR h.blocking_session_id = 0)
533+
));
625534
END;
626535
END; /* End of filter logic */
627536

@@ -633,10 +542,10 @@ For more info, visit http://FirstResponderKit.org
633542
+ N' session(s) for '
634543
+ CAST(ISNULL(DATEDIFF(SECOND, COALESCE(t.start_time, t.last_request_start_time), GETDATE()), 0) AS NVARCHAR(10))
635544
+ N' seconds.'
636-
FROM #sp_kill_sessions t
545+
FROM #hitlist t
637546
CROSS APPLY (
638547
SELECT COUNT(*) AS cnt
639-
FROM #sp_kill_sessions blocked
548+
FROM #hitlist blocked
640549
WHERE blocked.blocking_session_id = t.session_id
641550
) blocked_count
642551
WHERE t.KillRecommended = 1
@@ -645,7 +554,7 @@ For more info, visit http://FirstResponderKit.org
645554
AND (t.Reason IS NULL OR t.Reason = N'Targeted by @SPID parameter.');
646555

647556
/* Sleeping with open transactions */
648-
UPDATE #sp_kill_sessions
557+
UPDATE #hitlist
649558
SET Reason = N'Sleeping session with '
650559
+ CAST(open_transaction_count AS NVARCHAR(10))
651560
+ N' open transaction(s), idle for '
@@ -657,7 +566,7 @@ For more info, visit http://FirstResponderKit.org
657566
AND Reason IS NULL;
658567

659568
/* Long-running read-only */
660-
UPDATE #sp_kill_sessions
569+
UPDATE #hitlist
661570
SET Reason = N'Long-running read-only query: running for '
662571
+ CAST(ISNULL(DATEDIFF(SECOND, COALESCE(start_time, last_request_start_time), GETDATE()), 0) AS NVARCHAR(10))
663572
+ N' seconds'
@@ -671,7 +580,7 @@ For more info, visit http://FirstResponderKit.org
671580
AND Reason IS NULL;
672581

673582
/* Long-running write queries */
674-
UPDATE #sp_kill_sessions
583+
UPDATE #hitlist
675584
SET Reason = N'Long-running query: running for '
676585
+ CAST(ISNULL(DATEDIFF(SECOND, COALESCE(start_time, last_request_start_time), GETDATE()), 0) AS NVARCHAR(10))
677586
+ N' seconds, writes: ' + CAST(ISNULL(writes, 0) AS NVARCHAR(20))
@@ -685,13 +594,13 @@ For more info, visit http://FirstResponderKit.org
685594
AND Reason IS NULL;
686595

687596
/* Catch-all for anything that matched filters but wasn't categorized above */
688-
UPDATE #sp_kill_sessions
597+
UPDATE #hitlist
689598
SET Reason = N'Matched filter criteria.'
690599
WHERE KillRecommended = 1
691600
AND Reason IS NULL;
692601

693602
/* Clear KillCommand for sessions we're NOT recommending to kill */
694-
UPDATE #sp_kill_sessions
603+
UPDATE #hitlist
695604
SET KillCommand = NULL,
696605
FreeProcCacheCommand = NULL
697606
WHERE KillRecommended = 0;
@@ -709,18 +618,18 @@ For more info, visit http://FirstResponderKit.org
709618
CASE WHEN @OrderBy = 'tempdb' THEN CAST(ISNULL(tempdb_allocations_mb, 0) AS BIGINT) END DESC,
710619
CASE WHEN @OrderBy = 'transactions' THEN ISNULL(open_transaction_count, 0) END DESC
711620
) AS rn
712-
FROM #sp_kill_sessions
621+
FROM #hitlist
713622
WHERE KillRecommended = 1
714623
)
715624
UPDATE cte SET OrderByNum = rn;
716625

717626
/*-------------------------------------------------------
718627
Section 9: Rollback Warning
719628
-------------------------------------------------------*/
720-
IF EXISTS (SELECT 1 FROM #sp_kill_sessions WHERE [status] = 'rollback')
629+
IF EXISTS (SELECT 1 FROM #hitlist WHERE [status] = 'rollback')
721630
BEGIN
722631
DECLARE @RollbackCount INT;
723-
SELECT @RollbackCount = COUNT(*) FROM #sp_kill_sessions WHERE [status] = 'rollback';
632+
SELECT @RollbackCount = COUNT(*) FROM #hitlist WHERE [status] = 'rollback';
724633
SET @msg = N'WARNING: ' + CAST(@RollbackCount AS NVARCHAR(10))
725634
+ N' session(s) are currently rolling back. These will not be killed.';
726635
RAISERROR(@msg, 0, 1) WITH NOWAIT;
@@ -809,7 +718,7 @@ For more info, visit http://FirstResponderKit.org
809718
start_time, last_request_start_time, last_request_end_time, command, sql_text,
810719
sql_handle, plan_handle, query_plan, live_query_plan,
811720
transaction_isolation_level, is_read_only, FreeProcCacheCommand
812-
FROM #sp_kill_sessions
721+
FROM #hitlist
813722
ORDER BY KillRecommended DESC, ISNULL(OrderByNum, 2147483647), session_id;';
814723

815724
EXEC(@StringToExecute);
@@ -820,7 +729,7 @@ For more info, visit http://FirstResponderKit.org
820729
-------------------------------------------------------*/
821730
IF @ExecuteKills = 'Y'
822731
BEGIN
823-
SELECT @TotalKills = COUNT(*) FROM #sp_kill_sessions WHERE KillRecommended = 1;
732+
SELECT @TotalKills = COUNT(*) FROM #hitlist WHERE KillRecommended = 1;
824733

825734
IF @TotalKills = 0
826735
BEGIN
@@ -833,7 +742,7 @@ For more info, visit http://FirstResponderKit.org
833742

834743
DECLARE kill_cursor CURSOR LOCAL FAST_FORWARD FOR
835744
SELECT session_id, plan_handle, sql_handle, start_time, last_request_start_time
836-
FROM #sp_kill_sessions
745+
FROM #hitlist
837746
WHERE KillRecommended = 1
838747
ORDER BY OrderByNum;
839748

@@ -907,7 +816,7 @@ For more info, visit http://FirstResponderKit.org
907816
SET @KillEndTime = GETDATE();
908817

909818
/* Update temp table with kill results */
910-
UPDATE #sp_kill_sessions
819+
UPDATE #hitlist
911820
SET KillStartedTime = @KillStartTime,
912821
KillEndedTime = @KillEndTime,
913822
KillError = @KillError
@@ -932,7 +841,7 @@ For more info, visit http://FirstResponderKit.org
932841
ot.KillEndedTime = t.KillEndedTime,
933842
ot.KillError = t.KillError
934843
FROM ' + @ObjectFullName + N' ot
935-
INNER JOIN #sp_kill_sessions t ON ot.session_id = t.session_id
844+
INNER JOIN #hitlist t ON ot.session_id = t.session_id
936845
AND ot.CheckDate = t.CheckDate
937846
AND ot.ServerName = t.ServerName
938847
WHERE t.KillRecommended = 1;';
@@ -958,7 +867,7 @@ For more info, visit http://FirstResponderKit.org
958867
command, sql_text, sql_handle, plan_handle,
959868
query_plan, live_query_plan,
960869
transaction_isolation_level, is_read_only, FreeProcCacheCommand
961-
FROM #sp_kill_sessions
870+
FROM #hitlist
962871
ORDER BY KillRecommended DESC, ISNULL(OrderByNum, 2147483647), session_id;
963872

964873
END;

0 commit comments

Comments
 (0)