mediumLocking

LCK_M_RS_S_ABORT_BLOCKERS Wait Type Explained

LCK_M_RS_S_ABORT_BLOCKERS wait type occurs during SQL Server DDL operations with WAIT_AT_LOW_PRIORITY. Learn diagnosis, fixes, and prevention strategies.

Quick Answer

LCK_M_RS_S_ABORT_BLOCKERS occurs when a task waits for a shared range lock with abort blockers on key values during low-priority DDL operations like ALTER TABLE or ALTER INDEX with WAIT_AT_LOW_PRIORITY. This wait type is specific to SQL Server 2014+ and indicates blocking during schema modification attempts that use the abort blockers mechanism.

Root Cause Analysis

This wait type emerges from SQL Server's low-priority wait infrastructure introduced in SQL Server 2014. When executing DDL operations with the WAIT_AT_LOW_PRIORITY option and ABORT_BLOCKERS action, the lock manager requests shared range locks (RS) with special abort blocker semantics on index key ranges.

The lock manager maintains separate queues for normal lock requests and low-priority requests. When ABORT_BLOCKERS is specified, SQL Server first attempts to acquire the necessary locks at low priority. If blocking occurs, the system waits for the specified timeout period. Upon timeout expiration, the lock manager identifies and terminates sessions holding incompatible locks (the "blockers"), then resubmits the lock request.

Range locks protect key intervals in B-tree structures, preventing phantom reads and maintaining isolation. The RS (Range-Shared) component locks the range between the current key and the previous key, while the S (Shared) component locks the actual key value. The ABORT_BLOCKERS suffix indicates these locks participate in the low-priority wait mechanism.

SQL Server 2016 and later versions improved the efficiency of this mechanism by reducing lock escalation overhead during the abort process. In SQL Server 2019+, the query processor better estimates timeout durations based on historical blocking patterns.

The scheduler assigns these requests to worker threads that monitor both the lock acquisition and timeout conditions. Buffer pool involvement occurs when the lock manager needs to access index pages to determine key ranges, potentially causing additional waits if pages require physical I/O.

AutoDBA checks Low-priority DDL operation timeouts, blocking session patterns, and index maintenance scheduling across your entire SQL Server instance in 60 seconds. Download the free diagnostic script and see what else needs attention.

Diagnostic Queries

-- Identify current sessions waiting for LCK_M_RS_S_ABORT_BLOCKERS
SELECT 
    r.session_id,
    r.wait_type,
    r.wait_time,
    r.blocking_session_id,
    s.program_name,
    t.text,
    r.wait_resource
FROM sys.dm_exec_requests r
INNER JOIN sys.dm_exec_sessions s ON r.session_id = s.session_id
CROSS APPLY sys.dm_exec_sql_text(r.sql_handle) t
WHERE r.wait_type = 'LCK_M_RS_S_ABORT_BLOCKERS';
-- Find ALTER statements with WAIT_AT_LOW_PRIORITY currently executing
SELECT 
    r.session_id,
    r.command,
    r.percent_complete,
    r.estimated_completion_time,
    t.text,
    r.wait_type,
    r.wait_time
FROM sys.dm_exec_requests r
CROSS APPLY sys.dm_exec_sql_text(r.sql_handle) t
WHERE t.text LIKE '%WAIT_AT_LOW_PRIORITY%'
   OR r.wait_type = 'LCK_M_RS_S_ABORT_BLOCKERS';
-- Historical wait statistics for this wait type
SELECT 
    wait_type,
    waiting_tasks_count,
    wait_time_ms,
    max_wait_time_ms,
    signal_wait_time_ms,
    wait_time_ms / NULLIF(waiting_tasks_count, 0) as avg_wait_ms
FROM sys.dm_os_wait_stats 
WHERE wait_type = 'LCK_M_RS_S_ABORT_BLOCKERS';
-- Lock details for affected objects
SELECT 
    l.resource_type,
    l.resource_description,
    l.request_mode,
    l.request_status,
    s.session_id,
    s.program_name,
    t.text
FROM sys.dm_tran_locks l
INNER JOIN sys.dm_exec_sessions s ON l.request_session_id = s.session_id
CROSS APPLY sys.dm_exec_sql_text(s.most_recent_sql_handle) t
WHERE l.request_mode LIKE '%RS%'
   OR s.session_id IN (
       SELECT session_id 
       FROM sys.dm_exec_requests 
       WHERE wait_type = 'LCK_M_RS_S_ABORT_BLOCKERS'
   );
-- Monitor active transactions that might be blocking DDL
SELECT 
    t.transaction_id,
    t.transaction_begin_time,
    s.session_id,
    s.program_name,
    r.command,
    sql.text,
    t.transaction_state
FROM sys.dm_tran_active_transactions t
INNER JOIN sys.dm_tran_session_transactions st ON t.transaction_id = st.transaction_id
INNER JOIN sys.dm_exec_sessions s ON st.session_id = s.session_id
LEFT JOIN sys.dm_exec_requests r ON s.session_id = r.session_id
OUTER APPLY sys.dm_exec_sql_text(r.sql_handle) sql
WHERE t.transaction_begin_time < DATEADD(minute, -5, GETDATE())
ORDER BY t.transaction_begin_time;

Fix Scripts

Increase timeout duration for low-priority operations

-- Modify existing ALTER statements to use longer timeout
-- Replace existing WAIT_AT_LOW_PRIORITY settings
ALTER INDEX [IX_YourIndex] ON [YourTable] REBUILD 
WITH (
    ONLINE = ON,
    WAIT_AT_LOW_PRIORITY (
        MAX_DURATION = 10 MINUTES,  -- Increased from default
        ABORT_AFTER_WAIT = ABORT_BLOCKERS
    )
);

Test this in development first. Longer timeouts reduce frequency of aborts but may delay DDL completion.

Kill specific blocking sessions manually

-- Use with extreme caution - verify session impact first
DECLARE @BlockingSessionId INT;
SELECT @BlockingSessionId = blocking_session_id
FROM sys.dm_exec_requests 
WHERE wait_type = 'LCK_M_RS_S_ABORT_BLOCKERS'
AND blocking_session_id > 0;

-- Verify what the blocking session is doing
SELECT s.session_id, s.program_name, t.text
FROM sys.dm_exec_sessions s
CROSS APPLY sys.dm_exec_sql_text(s.most_recent_sql_handle) t
WHERE s.session_id = @BlockingSessionId;

-- Kill only after verification
-- KILL @BlockingSessionId;

This terminates user connections. Verify the blocking session's activity before executing KILL.

Switch to SELF termination strategy

-- Change abort strategy to terminate the DDL operation instead
ALTER INDEX [IX_YourIndex] ON [YourTable] REBUILD 
WITH (
    ONLINE = ON,
    WAIT_AT_LOW_PRIORITY (
        MAX_DURATION = 5 MINUTES,
        ABORT_AFTER_WAIT = SELF  -- Changed from ABORT_BLOCKERS
    )
);

SELF causes the DDL operation to fail rather than killing blockers. Safer for production but DDL may not complete.

Monitor and retry pattern

-- Implement retry logic for failed DDL operations
DECLARE @RetryCount INT = 0, @MaxRetries INT = 3;
DECLARE @Success BIT = 0;

WHILE @RetryCount < @MaxRetries AND @Success = 0
BEGIN
    BEGIN TRY
        ALTER INDEX [IX_YourIndex] ON [YourTable] REBUILD 
        WITH (
            ONLINE = ON,
            WAIT_AT_LOW_PRIORITY (
                MAX_DURATION = 2 MINUTES,
                ABORT_AFTER_WAIT = SELF
            )
        );
        SET @Success = 1;
        PRINT 'Index rebuild completed successfully';
    END TRY
    BEGIN CATCH
        SET @RetryCount = @RetryCount + 1;
        PRINT 'Retry attempt ' + CAST(@RetryCount AS VARCHAR(10));
        WAITFOR DELAY '00:02:00'; -- Wait 2 minutes before retry
    END CATCH
END;

Implements automatic retry with delays. Adjust timing based on your workload patterns.

AutoDBA generates fix scripts like these automatically, with impact estimates and rollback SQL included.

Prevention

Schedule DDL operations during maintenance windows when fewer concurrent transactions are active. Long-running transactions are the primary cause of these waits, so implement transaction timeout policies for application connections.

Configure appropriate MAX_DURATION values based on your workload patterns. Start with 5-minute timeouts and adjust based on historical blocking duration. Monitor sys.dm_os_wait_stats regularly to identify trends in wait frequency and duration.

Use ABORT_AFTER_WAIT = SELF for critical production systems where killing user sessions is unacceptable. This allows applications to retry DDL operations during less busy periods rather than disrupting user transactions.

Implement application-level connection pooling with shorter connection lifetimes to reduce the likelihood of long-running transactions. Set appropriate transaction isolation levels, avoiding unnecessary SERIALIZABLE isolation that creates additional range locks.

Consider using SQL Server 2019+ resumable online index operations for large tables. These operations can pause and resume, reducing the impact of blocking scenarios. Enable Query Store to identify queries that frequently hold locks during DDL windows.

For frequently modified tables, evaluate partitioning strategies that allow partition-level maintenance operations instead of full table operations. This reduces the scope of locking and minimizes blocking potential.

Need hands-on help?

Dealing with persistent lck_m_rs_s_abort_blockers issues across your environment? Samix Technology provides hands-on SQL Server performance consulting with 15+ years of production DBA experience.

Related Pages