All posts
Deep Dive · Debugging

Are ABORT_AFTER_WAIT's victims logged?

Testing whether SQL Server logs ABORT_AFTER_WAIT = BLOCKERS victims in the error log the same way KILL does, with a reproducible WAIT_AT_LOW_PRIORITY demo.

Tom · 3 min read SQL 2014+
Are ABORT_AFTER_WAIT's victims logged?

In SQL Server, using the KILL command to terminate a session results in an entry being logged in the error log. This raises the question: Does the ALTER INDEX REBUILD command with the WAIT_AT_LOW_PRIORITY option also log its actions in the error log?

KILL demo

Let's start with a KILL example. I'll open two connections which I'll refer to as command and victim - note the victim's session ID (SELECT @@SPID). For me, it's 52

Then simply run KILL 52 from your command session.

You can then read and filter the error log with this command

EXEC sp_readerrorlog 0, 1, N'kill'

And this is the output. Error log: KILL logged one row - Process ID 52 killed by host process ID 27180

WAIT_AT_LOW_PRIORITY demo

For the second demo, we'll:

  • Create a table with a named PK
  • Fill it with some rows
  • Start a reading transaction in the victim session
  • Run ALTER INDEX REBUILD with WAIT_AT_LOW_PRIORITY and ABORT_AFTER_WAIT = BLOCKERS
  • Check error log again to see if it was logged
DROP TABLE IF EXISTS dbo.TestTable
CREATE TABLE dbo.TestTable
(
    Id int
    , Filler char(100)
    , CONSTRAINT PK_dbo_TestTable PRIMARY KEY CLUSTERED (Id)
)

; -- Previous statement must be properly terminated
WITH
  L0   AS(SELECT 1 AS c UNION ALL SELECT 1),
  L1   AS(SELECT 1 AS c FROM L0 CROSS JOIN L0 AS B),
  L2   AS(SELECT 1 AS c FROM L1 CROSS JOIN L1 AS B),
  L3   AS(SELECT 1 AS c FROM L2 CROSS JOIN L2 AS B),
  L4   AS(SELECT 1 AS c FROM L3 CROSS JOIN L3 AS B),
  L5   AS(SELECT 1 AS c FROM L4 CROSS JOIN L4 AS B),
  Nums AS(SELECT ROW_NUMBER() OVER(ORDER BY (SELECT NULL)) AS n FROM L5)
, tally AS (SELECT TOP (5000) n FROM Nums ORDER BY n)
INSERT INTO dbo.TestTable WITH (TABLOCKX)
  (Id, Filler)
SELECT 
      n
    , CAST(n AS char(100))
FROM tally 

In the victim session, open a new reading transaction. Note the session ID - for me it's 66, which is the one we'll spot highlighted in the log shortly.

BEGIN TRAN
    SELECT * FROM dbo.TestTable (HOLDLOCK)

Back in the command session we'll run the ALTER INDEX. This will run for a minute.

Warning ABORT_AFTER_WAIT = BLOCKERS force-kills every transaction blocking the rebuild. It requires the ALTER ANY CONNECTION permission - without it you'll get error 11423.
ALTER INDEX [PK_dbo_TestTable] 
ON [dbo].[TestTable] 
REBUILD WITH 
(
    ONLINE=ON 
    (
        WAIT_AT_LOW_PRIORITY
        (
            MAX_DURATION = 1 MINUTES
            , ABORT_AFTER_WAIT = BLOCKERS
        )
    )
)

We can check the error log with the same query as before and the result is:

Error log: ALTER INDEX REBUILD generates three entries - statement started, BLOCKERS lock request on database_id 6, and Process ID 66 killed by ABORT_AFTER_WAIT = BLOCKERS (highlighted row)

Conclusion

Yes, it's logged - and in more detail than KILL. Where KILL writes a single entry, ABORT_AFTER_WAIT = BLOCKERS generates three: the ALTER INDEX REBUILD start, a lock request (with database_id and object_id), and the killed process ID. That's enough to trace both the victim and the statement that caused it.

Note I only tested ABORT_AFTER_WAIT = BLOCKERS here. SELF (which aborts the ALTER INDEX itself) and NONE (wait indefinitely) may log differently.

Thank you for reading

Tom
Tom, TSQL Dev

SQL Server consultant from Czechia.

Give me a problem where the answer isn't obvious and the evidence doesn't add up. That's my idea of a good time.