Skip to content

Deep Dive into the LCK_M_S Wait Type in SQL Server

In SQL Server, wait types are critical indicators of performance bottlenecks, revealing what a session is waiting on during query or task execution. Among these, the LCK_M_S wait type is a common locking-related wait that can significantly impact database performance in high-concurrency environments. This blog post provides an in-depth exploration of the LCK_M_S wait type, including its definition, causes, performance implications, diagnostic techniques, and advanced mitigation strategies.

What is the LCK_M_S Wait Type?

The LCK_M_S wait type indicates that a SQL Server session is waiting to acquire a Shared (S) lock on a resource, such as a table, page, or row. Shared locks are used for read operations (e.g., SELECT queries), allowing multiple sessions to read the same data concurrently without modifying it. However, a session encounters an LCK_M_S wait when another session holds an incompatible lock—typically an Exclusive (X) or Update (U) lock—on the same resource, preventing the Shared lock from being granted.

SQL Server’s locking mechanism ensures data consistency by coordinating access to resources. The lock compatibility matrix determines which locks can coexist. For example, Shared locks are compatible with other Shared locks but incompatible with Exclusive locks, which are used for data modifications (e.g., INSERT, UPDATE, DELETE). The LCK_M_S wait type is thus a symptom of lock contention, where read operations are blocked by write operations or vice versa.

Common Causes of LCK_M_S Waits

LCK_M_S waits arise in scenarios where lock contention occurs, including:

  • Long-Running Write Transactions: A transaction performing large updates or deletes holds Exclusive locks for an extended period, blocking sessions needing Shared locks for reads.
  • High Concurrency Workloads: In busy systems, multiple sessions reading and modifying the same data (e.g., frequently accessed tables) lead to frequent lock conflicts.
  • Index Maintenance Operations: Tasks like index rebuilds or reorganizations often acquire Exclusive or Update locks at the table or page level, blocking read operations.
  • Inefficient Queries: Queries that scan entire tables or lack proper indexes hold locks longer than necessary, increasing the likelihood of blocking read operations.
  • Blocking Chains: A chain of blocked sessions where one transaction’s lock blocks others, which in turn block additional sessions, amplifying LCK_M_S waits.
  • Schema Modifications: Operations like ALTER TABLE or adding indexes can take Schema Modification (Sch-M) locks, which are highly restrictive and block Shared locks.
  • Triggers or Cascading Actions: Triggers or foreign key constraints with cascading updates/deletes can extend transaction durations, holding locks longer.

Impact on Performance

High LCK_M_S wait times can have significant consequences, including:

  • Increased Query Latency: Read queries waiting for Shared locks experience delays, leading to slower response times.
  • Reduced Transaction Throughput: In high-concurrency environments, lock contention can bottleneck transaction processing, lowering overall system performance.
  • Application Timeouts: Prolonged blocking can cause application queries to timeout, resulting in errors and degraded user experience.
  • Deadlocks: Persistent lock contention may escalate into deadlocks, where SQL Server terminates one session to resolve the conflict, potentially causing application retries or failures.

While some locking is inevitable in a multi-user database, excessive LCK_M_S waits indicate contention that requires investigation and optimization.

Diagnosing LCK_M_S Waits

Effective diagnosis of LCK_M_S waits involves identifying the blocking sessions, locked resources, and underlying queries. Below are key diagnostic tools and techniques:

1. sys.dm_os_wait_stats

This Dynamic Management View (DMV) provides cumulative Wait Statistics for the SQL Server instance. To monitor LCK_M_S waits, use:

SELECT     wait_type,     wait_time_ms,     waiting_tasks_count,     wait_time_ms / NULLIF(waiting_tasks_count, 0) AS avg_wait_time_msFROM sys.dm_os_wait_statsWHERE wait_type = 'LCK_M_S';    

Key columns:

  • wait_time_ms: Total wait time in milliseconds since the last server restart or wait stats reset.
  • waiting_tasks_count: Number of tasks that experienced LCK_M_S waits.
  • avg_wait_time_ms: Average wait time per task, indicating the severity of blocking.

To track changes over time, capture deltas between snapshots:

-- Store baseline statsSELECT wait_type, wait_time_ms, waiting_tasks_countINTO #WaitStatsBaselineFROM sys.dm_os_wait_statsWHERE wait_type = 'LCK_M_S';-- Wait for a period (e.g., 5 minutes)WAITFOR DELAY '00:05:00';-- Compare with current statsSELECT     w.wait_type,     w.wait_time_ms - b.wait_time_ms AS delta_wait_time_ms,    w.waiting_tasks_count - b.waiting_tasks_count AS delta_waiting_tasksFROM sys.dm_os_wait_stats wJOIN #WaitStatsBaseline b ON w.wait_type = b.wait_typeWHERE w.wait_type = 'LCK_M_S';    

2. sys.dm_tran_locks

This DMV shows active locks and sessions waiting for locks, helping identify the resource and blocking session:

SELECT     resource_type,     DB_NAME(resource_database_id) AS database_name,     resource_description,     request_mode,     request_status,     request_session_idFROM sys.dm_tran_locksWHERE request_status = 'WAIT' AND request_mode = 'S';    

Key columns:

  • resource_type: Type of resource (e.g., TABLE, PAGE, ROW).
  • resource_description: Specific resource identifier, such as page or object ID.
  • request_status: Indicates if the lock is waiting or granted.
  • request_session_id: Session ID waiting for the lock.

3. sys.dm_exec_requests and sys.dm_exec_sessions

Identify currently blocked sessions and their blocking counterparts:

SELECT     r.session_id,     r.blocking_session_id,     r.wait_type,     r.wait_time,     r.sql_handle,     t.text AS query_text,    s.login_name,     s.program_nameFROM sys.dm_exec_requests rCROSS APPLY sys.dm_exec_sql_text(r.sql_handle) tJOIN sys.dm_exec_sessions s ON r.session_id = s.session_idWHERE r.wait_type = 'LCK_M_S';    

This query retrieves the blocking session ID, the query causing the block, and session details like the application or user. To investigate the blocking session, repeat the query for the blocking_session_id.

4. Extended Events

For granular analysis, use Extended Events to capture lock acquisition and release events:

CREATE EVENT SESSION [TrackLockWaits] ON SERVERADD EVENT sqlserver.lock_acquired (    WHERE sqlserver.database_id = 5 AND mode = 'S'), -- Filter for specific database and Shared locksADD EVENT sqlserver.lock_released,ADD EVENT sqlserver.blocked_process_reportADD TARGET package0.ring_buffer;ALTER EVENT SESSION [TrackLockWaits] ON SERVER STATE = START;    

The blocked_process_report event provides detailed information about blocking scenarios, including the blocked and blocking queries. Configure the blocked process threshold via:

sp_configure 'show advanced options', 1;RECONFIGURE;sp_configure 'blocked process threshold', 5; -- Seconds to wait before reportingRECONFIGURE;    

5. Activity Monitor

For a quick overview, use SQL Server Management Studio’s Activity Monitor to view blocked and blocking sessions in real-time, though it’s less detailed than DMVs.

Advanced Troubleshooting and Mitigation Strategies

To reduce LCK_M_S waits, consider the following advanced strategies:

1. Optimize Transaction Management

Minimize lock duration by:

  • Keeping transactions short and committing promptly.
  • Breaking large transactions (e.g., massive UPDATEs) into smaller batches to reduce lock hold times.
  • Avoiding user input or network delays within transactions.

2. Enhance Query Performance

Reduce lock contention by optimizing queries:

  • Add covering or filtered indexes to minimize table scans and reduce the number of locked resources.
  • Use query hints like NOLOCK cautiously for non-critical reads, but beware of dirty reads.
  • Analyze execution plans to identify inefficient operations, such as scans or key lookups.

3. Adjust Transaction Isolation Levels

Modify isolation levels to reduce Shared lock contention:

  • Read Committed Snapshot Isolation (RCSI): Uses row versioning in tempdb to provide consistent reads without Shared locks, reducing LCK_M_S waits. Enable with:

    ALTER DATABASE YourDatabase SET READ_COMMITTED_SNAPSHOT ON;        
  • Snapshot Isolation: Similar to RCSI but allows explicit snapshot transactions. Enable with:

    ALTER DATABASE YourDatabase SET ALLOW_SNAPSHOT_ISOLATION ON;        

    Note that both options increase tempdb usage and may require additional storage and I/O capacity.

4. Schedule Maintenance Operations

Perform I/O-intensive or lock-heavy tasks, such as index rebuilds or schema changes, during maintenance windows to avoid impacting production workloads.

5. Implement Proactive Monitoring

Set up alerts for blocking scenarios:

  • Use SQL Server Agent to create alerts based on the blocked process report.
  • Employ third-party monitoring tools to detect and notify on prolonged LCK_M_S waits or blocking chains.

6. Address Application Design

Work with developers to:

  • Reduce contention by accessing tables in a consistent order to prevent deadlocks.
  • Optimize application logic to avoid unnecessary data modifications or prolonged transactions.
  • Use connection pooling to manage session lifecycles efficiently.

Real-World Example

Consider an e-commerce database with a high-concurrency workload. Users report slow order queries, and sys.dm_os_wait_stats shows 1,000,000 ms of LCK_M_S waits over an hour. Using sys.dm_exec_requests, the DBA identifies a long-running UPDATE on the Orders table holding an Exclusive lock, blocking multiple SELECT queries needing Shared locks. The UPDATE is part of a nightly batch job that processes millions of rows in a single transaction.

The resolution involves splitting the UPDATE into smaller batches of 10,000 rows, reducing lock duration. Additionally, the DBA enables RCSI to allow reads to proceed without waiting for Shared locks. After these changes, LCK_M_S waits drop to negligible levels, and order queries execute faster.

Conclusion

The LCK_M_S wait type is a key indicator of lock contention in SQL Server, often caused by long-running transactions, high concurrency, or inefficient queries. By leveraging DMVs like sys.dm_os_wait_stats, sys.dm_tran_locks, and sys.dm_exec_requests, along with Extended Events, administrators can diagnose and resolve blocking issues. Advanced mitigation strategies, such as optimizing transactions, adjusting isolation levels, and proactive monitoring, can significantly reduce LCK_M_S waits, ensuring optimal database performance in demanding environments.

Have you faced challenges with LCK_M_S waits? Share your insights or questions in the comments below!

Need help with this or anything relating to SQL Server? The team at Stedman Solutions can help. Find out how with a free no risk 30 minute consultation with Steve Stedman.

Getting Help from Steve and the Stedman Solutions Team
We are ready to help. Steve and the team at Stedman Solutions are here to help with your SQL Server needs. Get help today by contacting Stedman Solutions through the free 30 minute consultation form.

Contact Info for Stedman Solutions, LLC. --- PO Box 3175, Ferndale WA 98248, Phone: (360)610-7833
Our Privacy Policy