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

LATCH_EX

(Back to main page…)

Description:

This wait type occurs when a thread is waiting for access to a non-page data structure so that it can modify the data structure. The thread cannot get access to the data structure because one or more other threads have it latched in share mode. The Latches Whitepaper in the sidebar on the right has a description of all latch modes and their compatibility with other latch modes.

(Books Online description: “Occurs when waiting for a EX (exclusive) latch. This does not include buffer latches or transaction mark latches. A listing of LATCH_* waits is available in sys.dm_os_latch_stats. Note that sys.dm_os_latch_stats groups LATCH_NL, LATCH_SH, LATCH_UP, LATCH_EX, and LATCH_DT waits together.”)

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 36 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:

A latch is a lightweight synchronization mechanism that provides synchronization between threads trying to read or change a data structure in SQL Server. There are three types of latches:

  • Latches on pages being read from disk (these are covered by the PAGEIOLATCH_XX wait types – see the PAGEIOLATCH_SH wait type for more details)
  • Latches on pages already in memory (these are covered by the PAGELATCH_XX wait types – see the PAGELATCH_EX wait type for more details)
  • Latches on non-page data structures (i.e. everything else)

The LATCH_SH and LATCH_EX wait types occur when a thread requires access to a non-page data structure (e.g., page buffers in the buffer pool (latch type = BUFFER), or the data structure that represents a database’s data and log files (latch type = FGCB_ADD_REMOVE)).

A latch is only held for the duration of the operation, unlike a lock which may be held until a transaction commits. One example of locks and latches – imagine a table where an update query has caused lock escalation so that a table X lock is held on the table. As the query continues updating more records in the table, it won’t acquire any more locks, but any data and index pages that are updated in memory must be EX (exclusive) latched before the update can occur. The latch acts as the synchronization mechanism to prevent two threads updating the page at the same time, or a thread reading the page while another is in the middle of updating it. Another example is if you run a select query using NOLOCK – although the query will not acquire S (share) locks at any level in the table, the threads must acquire SH (share) latches on pages before they can be read, to synchronize with possible concurrent updaters.

Similar examples exist for all non-page data structures, but it’s easier to explain using page latches.

Non-page latch waits correspond to LATCH_SH and LATCH_EX waits in the output from the sys.dm_os_wait_stats DMV, but that DMV doesn’t show which exact latch is the contention point. You can look in the sys.dm_os_waiting_tasks DMV for latch waits occurring in real time (use this script), and that DMV will show the name of the latch being waited for. You can then look in the SQL Server Latch Classes Library for that latch and get more guidance. Alternatively, you can look in the sys.dm_os_latch_stats DMV to see which latches have had the most aggregate contention (use this script) and then get more guidance from the latches library. It’s impossible to troubleshoot non-page latch contention without knowing which latch is the contention point.

Note: Only look at latch statistics and be concerned about latch contention if LATCH_EX and/or LATCH_SH are one of the top waits on your server. It’s very easy to get pulled off on a wild-goose chase by looking at latch statistics first.

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

  1. Waiting for the ACCESS_METHODS_DATASET_PARENT latch to get the next set of pages to scan (in this case, while scanning an index)
  2. Waiting for the DATABASE_MIRRORING_CONNECTION latch to send a message to a mirroring partner (in this case, the once-per-second ping to verify the partner is still available)
  3. Waiting for the LOG_MANAGER latch to grow the log file (in this case, while generating the LOP_BEGIN_XACT log record to start a transaction for modifying a record in a system table because a data file grew)

And many, many more stacks around the set of non-page latches.

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

  1. SOS_Task::PostWait+90
    EventInternal::Wait+1f9
    LatchBase::Suspend+633
    LatchBase::AcquireInternal+415
    IndexDataSetSession::SetupNextChildSubScan+bc
    IndexDataSetSession::StartScan+ea
    RowsetNewSS::EnsureStartOfScanLong+b1
    RowsetNewSS::FetchNextRow+36
    CQScanTableScanNew::GetRow+f2
    CQScanXProducerNew::GetRowHelper+53
    CQScanXProducerNew::GetRow+15
    FnProducerOpen+57
    FnProducerThread+8c3
    SubprocEntrypoint+a7f
    SOS_Task::Param::Execute+21e
    SOS_Scheduler::RunTask+a8
  2. SOS_Task::PostWait+90
    EventInternal::Wait+1f9
    LatchBase::Suspend+633
    LatchBase::AcquireInternal+415
    DbmTransport::SendNoFlowControl+5c
    DbmConnection::SendSSBMessageNoWait+185
    DbmConnection::SendPing+3ad
    LsConnectionStateMachine::OpenedAction+b2
    LsStateMachineBase::PostEvent+1d7
    LsStateMgr::ProcessEvents+113
    DbmDatabaseStateMgr::MasterThreadRoutine+303
    SOS_Task::Param::Execute+21e
    SOS_Scheduler::RunTask+a8
  3. SOS_Task::PostWait+90
    EventInternal::Wait+1f9
    LatchBase::Suspend+633
    SQLServerLogMgr::GrowAFile+184
    SQLServerLogMgr::ReserveAndAppend+292
    XdesRMReadWrite::GenerateLogRec+615
    XdesRMReadWrite::LogBeginXact+287
    XdesRMReadWrite::MakeActive+b0
    XdesRMReadWrite::GenerateLogRec+8f
    PageRef::ModifyRow+2c24
    PageRef::ModifyColumnsInternal+162
    IndexPageRef::Modify+307a
    BTreeRow::UpdateRecord+20ab
    IndexDataSetSession::SetDataInternal+9a03
    DatasetSession::SetData+16d
    RowsetNewSS::SetData+6a
    CMEDScanBase::FUpdateSingleRow+be
    CMEDScan::FUpdateRow+5ae
    CMEDCatPruFile::UpdateAttributes+87
    CMEDCatPruFile::UpdateAttributes+158
    TaskFileSizeChange::ProcessTskPkt+326
    OnDemandTaskContext::ProcessTskPkt+3e2
    SystemTaskEntryPoint+426
    OnDemandTaskContext::FuncEntryPoint+25
    SOS_Task::Param::Execute+21e
    SOS_Scheduler::RunTask+a8