Docs/Modules/Wait Statistics

Wait Statistics Module

How the Wait Statistics module collects, filters, baselines and reports SQL Server wait evidence read-only, with a reference for every control on the screen.

Looking for the subject, not the module?

This page documents the Wait Statistics module in SQL Performance Intelligence™. For the conceptual explanation of wait statistics themselves — the DMVs, the runnable T-SQL, delta capture, and a playbook per wait type — read SQL Server Wait Statistics: The Complete Guide.

Overview

Wait statistics are SQL Server’s own record of where its time went. Rather than inferring a bottleneck from counters and guesswork, you ask the engine directly: over this period, what were tasks waiting for, for how long, and how often? That record is the shortest path from “the database is slow” to a specific, testable cause — which is why wait-based analysis has been the default starting point for SQL Server performance troubleshooting for the better part of two decades.

This page covers both halves of the subject. The first half explains how the wait data itself works: what the columns mean, which wait types are worth your attention and what each one is telling you, which ones are pure noise, and why the cumulative totals in sys.dm_os_wait_stats mislead more often than they help. The second half documents the Wait Statistics module in SQL Performance Intelligence™, which collects and presents that evidence read-only.

If you want the runnable T-SQL — the collection query with the idle-wait filter, the delta capture, the Query Store attribution join, and a per-wait-type playbook of causes and fixes — that is in the companion guide, SQL Server Wait Statistics: The Complete Guide.

Fundamentals

How SQL Server Wait Statistics Work

Every task inside SQL Server is, at any given instant, in one of three states. It is running on a CPU scheduler; it is runnable, meaning it has everything it needs and is queued for a core; or it is suspended, waiting on something it does not yet have — a page from disk, a lock, a memory grant, a client to read the results already sitting in the output buffer.

Whenever a task leaves the running state, SQL Server records how long it was away and tags that time with a reason. Those tagged accumulations are the wait statistics, and they are exposed through sys.dm_os_wait_stats. There are several hundred wait types; a working server exercises perhaps a few dozen, and a handful will account for almost all of the time.

The useful signal is spread across four columns, and analyses that read only the first one routinely reach the wrong conclusion:

wait_time_ms
Total wait

Every millisecond spent waiting on this type, signal time included. This is the number that decides the ranking, and on its own it is the least informative of the four.

signal_wait_time_ms
Signal wait

The tail end of the wait: the resource has already arrived and the task is sitting in the runnable queue waiting for a CPU scheduler. This is pure scheduling delay, not resource delay.

waiting_tasks_count
Number of waits

How many times a task entered this wait. Divide total wait by this and you get the average wait — the difference between one forty-second stall and eight hundred thousand instant ones.

max_wait_time_ms
Worst single wait

The longest individual wait recorded for this type since the counters were last reset. A small total with a large maximum usually means a rare but severe event worth chasing.

One caveat that gets lost surprisingly often: waits tell you where time was spent, not that anything is wrong. An idle server accumulates waits happily, and a busy healthy server accumulates a great many. Every percentage you read is relative to the rest of the list, which is precisely why the filtering and baselining described further down matter more than the ranking itself.

Fundamentals

Signal Wait vs Resource Wait

A single wait usually has two parts. First the task waits for the thing it asked for. Then, once that thing arrives, it waits again — this time only for a free CPU scheduler to put it back on. SQL Server times both, and separating them is the fastest way to tell a resource problem from a CPU problem.

Resource wait
wait_time_ms − signal_wait_time_ms

Time spent genuinely waiting on the resource: the disk read, the lock, the memory grant. When this dominates, the wait type at the top of your list is naming a real constraint and is worth chasing on its own terms.

Signal wait
signal_wait_time_ms

Time spent in the runnable queue after the resource was already available. This is scheduling delay and nothing else. A high share across the whole instance means tasks are queueing for CPU, and the individual wait types are secondary to that.

As a rule of thumb, a signal share above roughly a fifth to a quarter of total wait time is worth investigating as CPU pressure — but only once the idle waits have been filtered out. Leave them in and the ratio is computed largely over background tasks that sleep on timers, which makes it meaningless. The module reports Total Wait, Signal Wait and Resource Wait side by side in the summary panel for exactly this reason, and drives its health state primarily from the resource-wait share.

Reference

SQL Server Wait Types That Matter

These are grouped by what they point at rather than ranked, because which wait matters depends entirely on the workload — a data warehouse and an OLTP order system have almost nothing in common at the top of the list. What does not change is what each type means and where to look once you see it.

CPU and scheduling

SOS_SCHEDULER_YIELD

A task exhausted its 4 ms scheduling quantum and yielded the CPU voluntarily so other tasks on the same scheduler could run. It is not a task being denied CPU — it is a task that had plenty and used all of it.

Where to look next: Expect a huge count with a tiny average. The usual source is a query burning through pages that are already in memory: large scans, nested loops over too many rows, a missing index that turned a seek into a scan. Chase the query, not the CPU.

CXPACKET

A thread in a parallel plan waited at an exchange operator. On SQL Server 2016 SP2 and 2017 onward the benign half of this — a consumer thread waiting for rows that have not been produced yet — was split out into CXCONSUMER, so what remains under CXPACKET is the more meaningful signal.

Where to look next: Parallelism is not a defect, and setting MAXDOP to 1 to make this number go away usually trades one problem for a slower one. Look at cost threshold for parallelism first, which still defaults to 5 and sends trivial queries parallel, then at row-distribution skew and stale statistics.

CXCONSUMER

The consumer side of a parallel exchange, waiting on its producer. On its own this is normal behavior of any parallel plan and carries almost no diagnostic weight.

Where to look next: Most analyses filter it out alongside the idle waits. If you are on a version that predates the split, the same traffic is folded into CXPACKET.

THREADPOOL

A task could not start because no worker thread was free. This is a symptom rather than a cause, and it is a severe one: with every worker consumed, new connections — including yours — may not get one either.

Where to look next: Look for what is holding the workers rather than for a way to raise max worker threads. A long blocking chain is the usual answer, since each blocked session keeps its worker parked for the duration.

Storage and I/O

PAGEIOLATCH_SH

A task is holding a latch on a buffer-pool page while the page is read in from disk, because the data it needs is not in memory. The SH variant is a read; PAGEIOLATCH_EX is the same wait during a write path.

Where to look next: Average wait is the number to read here. Sustained double-digit milliseconds points at storage latency, but the more common and far cheaper fix is to read fewer pages — indexing, plan shape, or a buffer pool too small to hold the working set.

WRITELOG

A commit is waiting for its log block to be hardened to the transaction log file. Nothing commits until this completes, so it sits directly in the path of write throughput.

Where to look next: Two independent causes. Log file latency is one. The other is transaction shape: ten thousand autocommit statements in a loop force ten thousand log flushes where one explicit transaction would force one.

IO_COMPLETION

I/O that is not a data-page read — reading the transaction log, and sort or hash operators spilling to tempdb when their memory grant proved too small.

Where to look next: When it climbs alongside memory-grant symptoms, treat it as evidence of spills rather than of a slow disk, and go look at cardinality estimates.

BACKUPIO

A backup task waiting on its backup device. Entirely expected while a backup is running, and meaningless outside that window.

Where to look next: Only worth investigating if backups are overrunning. Check the backup target throughput, buffer count, and whether compression is on.

Locking and latching

LCK_M_*

Waiting to acquire a lock, with the suffix naming the mode: LCK_M_S shared, LCK_M_X exclusive, LCK_M_U update, LCK_M_IX intent exclusive, LCK_M_SCH_M a schema modification queued behind readers. Whatever the suffix, this is blocking.

Where to look next: Cumulative lock waits tell you blocking happened, never who caused it. That answer only exists live, in the blocking chain, which is why this module pairs the counters with a chain view.

PAGELATCH_UP

Contention on a page that is already in memory — no disk is involved, despite how similar the name looks to PAGEIOLATCH. The UP mode on allocation pages is the classic tempdb signature: PFS, GAM and SGAM pages, addressed as 2:1:1, 2:1:2 and 2:1:3.

Where to look next: For tempdb allocation contention, the answer is multiple equally sized tempdb data files. SQL Server 2016 and later configure this at setup and enable uniform extent allocation by default.

PAGELATCH_EX

Exclusive in-memory page contention. On a user table this is usually last-page insert contention: many sessions inserting into a clustered index on an ever-increasing key all target the same trailing page.

Where to look next: On SQL Server 2019 and later, OPTIMIZE_FOR_SEQUENTIAL_KEY addresses this directly. Otherwise the fix is an index design that spreads inserts across more pages.

LATCH_EX

A latch that is not on a buffer page — an internal structure of some kind. The wait type alone does not say which.

Where to look next: The meaning lives in latch_class in sys.dm_os_latch_stats. Without that breakdown this wait type is not actionable.

Memory

RESOURCE_SEMAPHORE

A query is waiting for a memory grant before it can begin executing. The grant is sized at compile time from estimated row counts, so this is usually a cardinality-estimation problem wearing a memory costume.

Where to look next: A handful of queries with wildly overestimated grants can starve an otherwise healthy server. Find the largest grants and check their estimates against actuals before concluding the server needs more RAM.

RESOURCE_SEMAPHORE_QUERY_COMPILE

Waiting for memory in which to compile a plan, rather than to run one. It points at a workload that compiles constantly instead of reusing plans.

Where to look next: Look at ad-hoc statement volume, parameterisation, and whether optimize for ad hoc workloads is enabled.

CMEMTHREAD

Contention on a thread-safe internal memory object. It commonly accompanies heavy plan-cache churn on servers running large volumes of unparameterised ad-hoc SQL.

Where to look next: Usually resolves as a side effect of fixing the compilation volume rather than as a problem in its own right.

Network, replicas and external calls

ASYNC_NETWORK_IO

SQL Server has results ready and is waiting for the client to consume them. The name blames the network; the cause almost never is. It usually means an application is processing a result set row by row while holding it open, or running on a slow link.

Where to look next: This one is fixed in application code, not on the server. Consume the result set fully before processing it, and stop returning columns and rows nobody reads.

HADR_SYNC_COMMIT

A commit on the primary waiting for a synchronous-commit availability group secondary to harden the log record. By design, this ties your commit latency to the secondary’s log disk and the network between them.

Where to look next: Measure the secondary the way you would measure the primary. A slow log disk on a replica nobody looks at will show up as slow writes on the server everybody looks at.

OLEDB

SQL Server called out through an OLE DB provider. Linked server queries are the obvious source; DBCC CHECKDB is the non-obvious one, and its appearance during a scheduled integrity check is expected.

Where to look next: Correlate against the maintenance window before treating it as a linked-server problem.

PREEMPTIVE_OS_*

A worker left the SQL Server scheduler to make a Windows API call and ran preemptively while outside. Authentication, file system operations and extended stored procedures all produce these.

Where to look next: The suffix names the call. PREEMPTIVE_OS_AUTHENTICATIONOPS climbing, for instance, points at domain controller latency rather than anything inside the database engine.

Reference

Waits Worth Ignoring

SQL Server records background and timer tasks sleeping with the same diligence it records a query stalled on a lock. On an instance that has been up for months, these idle waits will occupy the entire top of an unfiltered list — a deadlock monitor that wakes every five seconds accumulates an enormous total while doing nothing at all. Filtering them out is not an optimization; it is the difference between a list that means something and a list that does not.

Commonly filtered idle and background waits
  • SLEEP_TASK
  • SLEEP_SYSTEMTASK
  • SLEEP_BPOOL_FLUSH
  • LAZYWRITER_SLEEP
  • WAITFOR
  • XE_TIMER_EVENT
  • XE_DISPATCHER_WAIT
  • REQUEST_FOR_DEADLOCK_SEARCH
  • SQLTRACE_INCREMENTAL_FLUSH_SLEEP
  • CHECKPOINT_QUEUE
  • DIRTY_PAGE_POLL
  • BROKER_TASK_STOP
  • BROKER_TO_FLUSH
  • BROKER_EVENTHANDLER
  • CLR_AUTO_EVENT
  • CLR_MANUAL_EVENT
  • DISPATCHER_QUEUE_SEMAPHORE
  • FT_IFTS_SCHEDULER_IDLE_WAIT
  • SP_SERVER_DIAGNOSTICS_SLEEP
  • QDS_ASYNC_QUEUE
  • QDS_SHUTDOWN_QUEUE
  • QDS_PERSIST_TASK_MAIN_LOOP_SLEEP
  • HADR_WORK_QUEUE
  • HADR_CLUSAPI_CALL
  • HADR_FILESTREAM_IOMGR_IOCOMPLETION
  • ONDEMAND_TASK_QUEUE
  • PWAIT_ALL_COMPONENTS_INITIALIZED

The list is not exhaustive and never will be — each major version adds wait types. Treat anything whose name contains SLEEP, QUEUE, IDLE or TIMER as suspect until you have a reason to believe otherwise. CXCONSUMER is usually filtered here too, for a different reason: it is real work, just not work that indicates a problem.

Methodology

Why Cumulative Wait Totals Mislead

sys.dm_os_wait_stats is cumulative since the last service restart, failover, or explicit DBCC SQLPERF('sys.dm_os_wait_stats', CLEAR). There is no time dimension in it whatsoever. On a server that has been up for three hundred days, the top of that list is a three-hundred-day average — it includes every index rebuild, every full backup, every month-end batch run, and every quiet Sunday. It cannot, even in principle, tell you anything about the slowdown that started an hour ago.

Two adjustments fix this, and they compose:

  • Take a delta. Capture the counters, wait out the window you care about, capture them again, and subtract. What is left describes that window and nothing else. This is what the module’s Set Baseline and the explicit Save Before / Save After comparison do, and it is why measuring a change means comparing two snapshots rather than reading one.
  • Normalise against uptime. Dividing total wait by seconds since the counters were reset gives you wait-seconds per second of server time, which is comparable between servers of different uptimes and, once you also divide by core count, between servers of different sizes. Raw millisecond totals are comparable to nothing.

The other structural limit is attribution. A server-level wait tells you the instance spent time on PAGEIOLATCH_SH; it does not tell you which query did it. Three sources close that gap: sys.dm_exec_requests for what is waiting right now, sys.dm_exec_session_wait_stats for per-session totals on SQL Server 2016 and later, and sys.query_store_wait_stats on 2017 and later, which attributes waits to a specific query and plan and is the only one of the three that retains history.

Methodology

From Dominant Wait to Actual Fix

A wait type is a direction, not a diagnosis. The sequence below is what turns one into the other, and skipping a step is how wait analysis acquires its reputation for producing confident wrong answers.

  1. Filter the idle waits first. Everything downstream is computed over what is left, including the signal-wait ratio.
  2. Read total and average together. A type holding sixty percent of total wait across forty million waits averaging a fifth of a millisecond is a completely different problem from sixty percent across three hundred waits averaging four hundred milliseconds. The first is volume; the second is latency. They have different fixes.
  3. Reduce to a window. Delta against a baseline, or against a before-snapshot, so that what you are looking at is the period in question rather than the server’s entire life.
  4. Check the signal share. If scheduling delay dominates, the specific wait types below it are largely downstream of CPU pressure and chasing them individually will waste your time.
  5. Attribute the wait to a query. Query Store wait stats, session wait stats, or live requests. Without this step you are tuning a server rather than a workload.
  6. Change one thing and re-measure. Same window, same filters, same comparison. Two simultaneous changes produce one uninterpretable result.

Where the wait profile points at live lock contention, cumulative counters have nothing more to give you and the investigation moves to the blocking chain — Blocking Analysis covers that path. Where it points at a specific plan shape, Query Statistics carries the query-level regression and plan evidence.

The Module

Wait Statistics in SQL Performance Intelligence™

The Wait Statistics module is the wait-centric diagnostics surface. It combines cumulative SQL Server wait data, active waiting sessions, blocking-chain analysis, historical trend snapshots, optional query-context correlation, and current-session threshold signals so you can identify the dominant source of performance pressure quickly. Every query it runs is read-only.

This module is most valuable alongside Query Statistics when you need wait-to-plan correlation, and Blocking Analysis when waits point to live blockers and chain depth.

What You Can Do
  • Inspect dominant wait types and wait-category pressure.
  • Review active waiting sessions and blocking chains.
  • Compare against a saved baseline or explicit before/after snapshots.
  • Configure current-session threshold signals, refresh-driven snapshots, and custom regex categories.
  • Export the current analysis to HTML, JSON, or Markdown.
Main Screen Areas
  1. Header card
  2. Filter bar
  3. Main content tabs
  4. Right-side insight panel
Screen 1

Main Wait Diagnostics Layout

The opening view combines the filter bar, top waits presentation, summary metrics, and the first layer of wait interpretation. This is the primary screen for deciding whether the dominant pressure is CPU, I/O, lock, memory, or network related.

Screen 2

Trend View for Historical Wait Direction

Trend view helps determine whether the dominant wait pattern is new, recurring, or gradually increasing — the question cumulative counters cannot answer on their own. The module prefers Query Store wait history when available and falls back to local snapshots when Query Store wait history is missing.

Screen 3

Blocking Chain Evidence

When lock-related waits or live request contention matters, the blocking tree helps explain whether root blockers and blocked sessions are responsible for the current wait profile. This is the step that converts an LCK_M_* total into a named session, which cumulative counters can never do.

Automation Screen Note

Current-Session Refresh and Admin Controls

The current public asset set does not include a clean standalone screenshot for the Automation tab, so this page describes those controls in text instead of showing a mismatched image. The available controls still include refresh-driven snapshots, a 5-second visible-view refresh option, custom wait categories, outbound targets, and the guarded admin-only wait reset flow. These controls do not run as a background service when the application or view is closed.

Screen 4

Wait Insights and Actionable Guidance

The right-side insight stack turns the current evidence into an operational narrative: threshold signals, dominant signatures, baseline deltas, wait-to-plan notes, outbound target status, and a short recommended action list.

Data Sources and Analysis Model

Core Wait Data
  • Uses SQL Server DMVs such as sys.dm_os_wait_stats, sys.dm_exec_requests, and sys.dm_exec_sessions.
  • Builds top-wait, wait-summary, wait-category, and current-wait views from refresh results.
  • Separates total wait, signal wait, resource wait, and active waiting-session evidence.
Historical Trend Source
  • Prefers Query Store wait history through sys.query_store_wait_stats.
  • Falls back to locally persisted snapshots when Query Store wait history is unavailable.
  • Trend source can therefore resolve to query_store, local_history, or none.
Blocking and Live Chains
  • Uses shared blocking services to explain active contention chains.
  • Shows root blockers and blocked sessions with database, login, wait, and wait-ms context.
  • Supports DB, App, and Min Wait filters when rendering live trees.
Query Context Mode
  • When opened with query context, waits can switch from server-level to query-correlated evidence.
  • The Wait / Plan panel becomes meaningful only in this mode.
  • This is why the module has distinct server-level and query-context behaviors.

Header, Filters, and Main Tabs

Header Card
  • Optional focus context label
  • Refresh
  • Set Baseline
  • Export
Filter Bar
  • Trend Window
  • DB Filter
  • App Filter
  • Min Wait
  • Apply Filter and progress label
Main Tabs
  1. Top Waits
  2. Trend & Blocking
  3. Automation
Top Waits Behavior
  • Rows show wait type, category, impact line, sparkline, wait time, tasks, percent, and max wait.
  • Display source can be cumulative waits, grouped current waits, or query-correlated waits.
  • Heuristic action hints help convert dominant waits into next-step investigation tasks.

Automation and Admin Controls

Scheduled Snapshot
  • Supports periodic snapshot and report generation.
  • Current UI exposes enabled state, interval, and Save Schedule.
  • Snapshot generation runs when refresh occurs and the configured interval is due.
5s Visible-View Refresh
  • Refreshes every 5 seconds only while this view remains open and visible.
  • It is not a background collector and stops when the view or desktop application is closed.
  • Exposes visible thresholds for total wait, lock wait, and blocked sessions.
  • The underlying service supports more alert fields than the main UI currently edits.
Custom Categories
  • Supports operator-defined regex-based wait groups.
  • Only enabled rules contribute to current custom-category totals.
  • Rules can be added or removed from both the Automation tab and the Actions panel.
Admin Clear Safety
  • Clear Wait Stats is the only destructive action in the module.
  • It requires an armed admin session, active connection, warning confirmation, and exact phrase entry.
  • The action runs server-wide counter reset behavior and is audit-logged.

Right-Side Insights

Summary and Categories
  • Summary shows Total Wait, Signal Wait, Resource Wait, and Current Waiters.
  • Health state is primarily driven by resource-wait percentage.
  • Wait Categories quickly summarize CPU, I/O, Lock, Latch, Memory, Network, Buffer, and Other pressure.
Insight Blocks
  • Alerts
  • Signature
  • Before / After
  • Actions
  • Wait / Plan
  • Outbound target status
  • Actionable Intelligence
Signature and Alerts
  • Alerts highlight threshold breaches, wait growth, and blocking risk signals.
  • Signature summarizes the dominant pattern with confidence and short evidence text.
  • Typical signature families include CPU pressure, I/O bottleneck, lock contention, and memory grant pressure.
Wait / Plan and Intelligence
  • Wait / Plan explains correlations such as lock waits with scans or I/O waits with spills and lookups.
  • Outbound target status summarizes configured destinations; delivery depends on the active desktop session.
  • Actionable Intelligence turns waits, alerts, signatures, baseline deltas, and trend direction into an operator playbook.

Sample AI Analysis Report

The current Wait Statistics asset set includes one exported HTML report. It can be opened directly in the browser or downloaded for offline review, handoff, or ticket attachment.

Detailed Control Reference

Buttons
  • Refresh
  • Set Baseline
  • Export
  • Apply Filter
  • Save Before
  • Save After
  • Compare
  • Custom Category
  • Remove Custom
  • Save Schedule
  • Save Thresholds
  • Add Category
  • Remove Category
  • Clear Wait Stats (Manual Admin)
  • Add Server Target
  • Remove Target
  • Push Metrics Now
Checkboxes
  • Scheduled Snapshot Enabled
  • Enable 5s Monitor (while view is visible)
  • Enable Admin Tools for this session
Comboboxes
  • Trend Window
  • DB Filter
  • App Filter
  • Display

Behavior Notes and Typical Workflow

Important Behavior Notes
  • DB, App, and Min Wait filters do not fully rewrite cumulative wait-summary totals.
  • Set Baseline is separate from explicit Save Before / Save After comparison.
  • Trend source can switch between Query Store, local history, and none.
  • Some alert and schedule fields exist in the service model but are not fully editable in the visible UI.
Typical Workflow
  1. Click Refresh and review Summary, Wait Categories, and Alerts.
  2. Inspect Top Waits to identify the dominant wait profile and suggested actions.
  3. Use Trend & Blocking to determine whether the issue is persistent or tied to live blockers.
  4. Capture a baseline or explicit before/after snapshots when measuring change impact.
  5. Use Automation for current-session thresholds, refresh-driven snapshots, and outbound targets.
  6. When opened from Query Statistics, use Wait / Plan to connect waits with a specific plan shape.
Common Questions

SQL Server Wait Statistics FAQ

What is a good wait statistics result?

There isn’t one. A server doing work always waits for something, so there is no threshold that separates healthy from unhealthy, and no wait type that is universally bad. What carries meaning is comparison: this window against a baseline window, this average wait against the same average last week, this wait’s share against what it was before you changed something.

Should I clear wait statistics?

Rarely, and never casually. DBCC SQLPERF('sys.dm_os_wait_stats', CLEAR) resets the counters server-wide and irreversibly, which also destroys the history of any monitoring tool reading the same DMV. Capturing two snapshots and subtracting gives you the same isolated window without the side effects. The honest use case is a controlled test where you want a clean starting point and know what else is collecting.

Is CXPACKET a problem?

It means parallelism happened, which is what parallelism is supposed to do on a large query. Treat it as a prompt to check two settings — cost threshold for parallelism, which still ships at a 1995-era default of 5, and MAXDOP — and to look for row-distribution skew, where one thread does most of the work while the others wait. Forcing MAXDOP to 1 removes the wait type and often makes the workload slower.

Does high PAGEIOLATCH_SH mean I need faster storage?

Sometimes, and it is worth checking the average wait per read before deciding. More often it means the workload is reading pages it should not need to read, or that the buffer pool cannot hold the working set. An index that turns a scan into a seek removes far more I/O wait than a faster disk does, and costs less.

How much history do the wait statistics DMVs keep?

None. sys.dm_os_wait_stats is a running total since the last service restart, failover, or explicit clear — there is no time dimension in it at all. History has to come from somewhere else: sys.query_store_wait_stats on SQL Server 2017 and later, which additionally attributes waits to a query and plan, or your own periodic snapshots.

Which wait types should I ignore?

The background and timer waits that accumulate while the server is idle — SLEEP_TASK, LAZYWRITER_SLEEP, XE_TIMER_EVENT, REQUEST_FOR_DEADLOCK_SEARCH, the QDS_ and BROKER_ queues, and their relatives. On a server with real uptime these will otherwise occupy the entire top of the list and hide everything that matters.

Related References

For deeper SQL Server investigation, pair this module with Query Statistics for query-level regression analysis, Blocking Analysis for chain-first lock investigation, and Dashboard for broader CPU, I/O, memory, and workload pressure context. For the SQL Server side of the subject rather than the module — the DMVs, the queries, delta capture and per-wait playbooks — the complete wait statistics guide goes considerably deeper.