(Republishing, or using this info in a commercial product/website, is prohibited without permission. All other uses are permitted. If in doubt, please ask.)

LCK_M_S

(Back to main page…)

Description:

This wait type is when a thread is waiting to acquire a Shared lock on a resource and there is at least one other lock in an incompatible mode granted on the resource to a different thread.

General locking information:

(Books Online description: “Occurs when a task is waiting to acquire a Shared lock.”)

Questions/comments on this wait type? Click here to send Paul an email, especially if you have any information to add to this topic.

Added in SQL Server version:

Pre-2005/2005

Removed in SQL Server version:

N/A

Extended Events wait_type value:

The map_key value in sys.dm_xe_map_values is 3 in all versions through 2014 RTM. After 2014 RTM, you must check the DMV to get the latest value as some map_key values have changed in later builds.

Other information:

General guidance around troubleshooting lock waits:

  • It is not possible to determine the lock resource from the sys.dm_os_wait_stats output. You can see the resource from sys.dm_os_waiting_tasks (using my script) or looking at the resource_description field of sys.dm_tran_locks where the request_status is ‘WAIT’.
  • You can use the blocked process report to get more detailed information on queries that are waiting for locks for a specified threshold (see here).
  • Look to see what is at the head of the blocking chain (i.e. the thread that’s holding the lock that’s blocking everyone) using a script (plenty of them available online – I don’t have a preferred one). What is that thread waiting for? Fixing that wait may help unravel the blocking. For example, a thread may be holding locks and committing a transaction, but there’s a synchronous mirror with a slow I/O subsystem so the mirror log write takes a long time, making the transaction commit take longer, and the locks take longer to be released, causing blocking.
  • Look for lock escalation, where an UPDATE transaction has escalated to a table X lock, causing widespread blocking.
  • Look for index operations causing table locks, and consider using online index operations (or if already using them, consider the WAIT_AT_LOW_PRIORITY feature in 2014+).
  • Look for code that specifies a TABLOCK (causes a table Shared lock) or TABLOCKX (causes a table Exclusive lock) hint.
  • Look for application code that will cause locks to be acquired and then waits for user input, or fails to commit a transaction for a long time.
  • Consider creating nonclustered indexes to remove row locks from the underlying heap/clustered index.
  • Consider using snapshot isolation or read committed snapshot isolation to allow readers to not take S/IS locks and reduce blocking.
  • Check the correct isolation level is being used as REPEATABLE_READ and SERIALIZABLE will hold S/IS locks until the end of a transaction.
  • Check for accidental use of the SERIALIZABLE isolation level, from using distributed transactions or incorrectly scoped .Net TransactionScope objects.

Specific guidance for LCK_M_S waits:

  • For a Shared lock, the resource could be a row, page, partition, table, or database.
  • Common blockers are a table X (Exclusive) lock from lock escalation occurring, or a SCH_M (Schema Modification) lock from an index build/rebuild.
  • If the resource is a table, any update or insert to the table will require a table IX (Intent Exclusive) lock, which will block a table S lock.
  • If the resource is a table, investigation why the thread is requiring a table S lock (e.g. use of TABLOCK hint or lock escalation in a restrictive isolation level).
  • All connections to a database acquire a database S lock to prevent the database from changing while there are connections to it.

Known occurrences in SQL Server (list number matches call stack list):

  1. Waiting for a Shared lock on a table
  2. Waiting for a Shared lock on a database (in this case, as part of background checkpoint processing)
  3. Waiting for a Shared lock on a row (in this case, while scanning the list of Service Broker queues)

And many other similar call stacks.

Abbreviated call stacks (list number matches known occurrences list):

  1. SOS_Task::PostWait+9e
    EventInternal<SuspendQueueSLock>::Wait+1fb
    LockOwner::Sleep+485
    lck_lockInternal+10ed
    MDL::LockObjectLocal+dbe
    SMD::LockObjectAndCheckVersion+98
    CRangeObject::XretSchemaChanged+54e
    CRangeTable::XretSchemaChanged+1f
    CEnvCollection::XretSchemaChanged+e1
    CXStmtQuery::XretSchemaChanged+168
    CXStmtSelect::XretExecute+1b1
    CMsqlExecContext::ExecuteStmts<1,1>+427
    CMsqlExecContext::FExecute+a43
    CSQLSource::Execute+86c
    process_request+a57
    process_commands+4a3
    SOS_Task::Param::Execute+21e
    SOS_Scheduler::RunTask+ab
  2. SOS_Task::PostWait+9e
    EventInternal<SuspendQueueSLock>::Wait+1fb
    LockOwner::Sleep+485
    lck_lockInternal+10ed
    XactWorkspaceImp::GetSharedDBLockFromLockManager+1f7
    XactWorkspaceImp::GetDBLockLocal+154
    XactWorkspaceImp::GetDBLock+5e
    lockdb+4a
    DBMgr::OpenDB+1ec
    CheckpointHelper+140
    CheckpointLoopWorker+da
    RegisterCheckPtWorker+133
    CheckpointLoop+d3
    CheckpointThread+55
    SOS_Task::Param::Execute+21e
    SOS_Scheduler::RunTask+ab
  3. SOS_Task::PostWait+9e
    EventInternal<SuspendQueueSLock>::Wait+1fb
    LockOwner::Sleep+485
    lck_lockInternal+10ed
    GetLock+1d8
    BTreeRow::AcquireLock+210
    IndexRowScanner::AcquireNextRowLock+ef
    IndexDataSetSession::GetNextRowValuesInternal+1265
    RowsetNewSS::GetNextRows+b7
    CMEDScan::FGetRow+9b
    CMIterObjects::GetNext+74
    CSbActivationMgr::CreateQueueMonitors+19e
    CActiveServiceBroker::BackgroundNotify+244
    CActiveServiceBrokerMgr::ASBInitializer+19b
    CActiveServiceBrokerMgr::CSbASBInitializer::IdempotentInvoke+26
    CSbTaskManager::HandleReusableTask+2b8
    CSbTask::TaskStart+14b
    CSbTask::BeginTaskStart+17
    SOS_Task::Param::Execute+21e
    SOS_Scheduler::RunTask+ab