Tag: DMVs

  • 5 SQL Server DMVs Every DBA Should Know for Performance Tuning

    5 SQL Server DMVs Every DBA Should Know for Performance Tuning

    Extended Events (previous lesson) capture what happened over a time window you chose to record. Dynamic Management Views answer a different, often more urgent question: what is the state of the server right now, and what has it accumulated since the last restart — no trace setup required, just a SELECT.

    5 DMVs, sketched out(what each one uniquely answers)dm_exec_query_statspriciest queries,historically (all runs)dm_exec_requestswhat’s running NOW,+ blocking_session_iddm_os_wait_statswhat the WHOLE serveris waiting ondm_db_index_usage_statsis THIS index actuallybeing used?dm_exec_sessionswho’s connected rightnow, and from where?the cleanup signal — one index, two numbers:user_updates: 50kseeks+scans: 0costs on every write,helps zero reads 🗑️ DROP?these counters resetto ZERO on every servicerestart — always checkuptime first! 📌

    1. Top Queries by Logical Reads

    SELECT TOP 10
        qs.total_logical_reads / qs.execution_count AS avg_logical_reads,
        qs.execution_count,
        SUBSTRING(st.text, (qs.statement_start_offset/2)+1,
            ((CASE qs.statement_end_offset WHEN -1 THEN DATALENGTH(st.text) ELSE qs.statement_end_offset END - qs.statement_start_offset)/2)+1) AS query_text
    FROM sys.dm_exec_query_stats qs
    CROSS APPLY sys.dm_exec_sql_text(qs.sql_handle) st
    ORDER BY avg_logical_reads DESC;

    This DMV accumulates statistics since the plan was cached, across every execution — which makes it fundamentally different from a single execution plan (Lesson 3): it answers “which query costs the most in aggregate,” not “why is this one specific run slow.”

    2. What’s Running Right Now

    SELECT session_id, status, command, wait_type, wait_time, blocking_session_id, total_elapsed_time
    FROM sys.dm_exec_requests
    WHERE session_id > 50; -- excludes internal system sessions

    A non-NULL blocking_session_id here is one of the most actionable single columns in this entire toolkit — it directly identifies which session is blocking which, the starting point for diagnosing the blocking scenarios covered fully in Chapter 9.

    3. What the Server Is Waiting On

    SELECT TOP 10 wait_type, wait_time_ms, waiting_tasks_count
    FROM sys.dm_os_wait_stats
    WHERE wait_type NOT LIKE '%SLEEP%'
    ORDER BY wait_time_ms DESC;

    This is server-wide, cumulative since the last restart or manual reset — a genuinely powerful “what’s the bottleneck category, in general” question. High PAGEIOLATCH_* waits point toward disk I/O pressure; high CXPACKET/CXCONSUMER points toward parallelism; high LCK_M_* points toward blocking. This single query is often the very first thing a DBA runs when investigating “the server feels slow.”

    4. Which Indexes Are Actually Used

    SELECT OBJECT_NAME(s.object_id) AS table_name, i.name AS index_name,
        s.user_seeks, s.user_scans, s.user_lookups, s.user_updates
    FROM sys.dm_db_index_usage_stats s
    JOIN sys.indexes i ON i.object_id = s.object_id AND i.index_id = s.index_id
    WHERE s.database_id = DB_ID();

    The Quick Reference

    DMV Answers
    sys.dm_exec_query_stats Which queries are most expensive, historically (aggregated across all executions)?
    sys.dm_exec_requests What’s running right now, and waiting on what?
    sys.dm_os_wait_stats What is the whole server spending time waiting on, cumulatively?
    sys.dm_db_index_usage_stats Is this specific index actually being used?
    sys.dm_exec_sessions Who’s connected right now, and from where?

    A high-value pattern: user_updates high but user_seeks + user_scans + user_lookups near zero identifies an index that costs on every write but never helps a read — a strong candidate to drop. This single comparison is one of the most reliably useful index-cleanup queries a DBA runs, because it’s the exact opposite of the covering-index tuning from Lesson 2: a genuinely wasted index, paid for on every INSERT/UPDATE, that no query ever benefits from.

    Common mistake: Treating sys.dm_db_index_usage_stats as permanent history. These counters reset to zero on every SQL Server service restart — a recently-restarted server can make a genuinely valuable index look “unused” simply because it hasn’t been queried yet since the restart. Always check server uptime before trusting a zero.
    Practice tip: Run query #4 against your own practice database, and find the index with the highest user_updates-to-usage ratio. Before actually dropping anything, cross-check it against sys.dm_exec_query_stats (query #1) to see if any expensive query might depend on it that simply hasn’t run recently — real index cleanup always needs more than one signal.

    Enjoyed this?

    Subscribe to get every new SQL Server lesson as soon as it’s published, and share it with a developer who’d find it useful.

    📡 Subscribe via RSS  | 
    Share on X  | 
    Share on LinkedIn  | 
    Share on Facebook

    Want the full structured course with quizzes, projects, and 10+ exercises per chapter? Check out SQL Server for Developers & DBAs, coming soon on this site.

  • SQL Server PerfMon Counters That Actually Matter, Plus the Complete DMV Toolkit

    SQL Server PerfMon Counters That Actually Matter, Plus the Complete DMV Toolkit

    Windows Performance Monitor exposes hundreds of SQL Server counters. Most are noise. Here are the handful worth an actual dashboard tile, plus every DMV this course has used, in one place.

    Four tools, four different questions(reach for the right one)WHAT’SWRONG?(start here)PerfMonIs there a TRENDover time?DMVsWhat’s the stateRIGHT NOW?Query StoreHow has THIS QUERYevolved over time?ExtendedEventsCapture a SPECIFICevent as it happensCommon mistake: treating Batch Requests/sec ashaving a ‘good’ absolute number. There isn’t one —it’s workload-specific. Only the TREND vs YOUR OWNbaseline matters, not some blog’s benchmark. 📌

    The PerfMon Counters Worth Watching

    Counter What a bad value means
    Page Life Expectancy Low = buffer pool pressure, pages evicted quickly (Module 1)
    Batch Requests/sec Your baseline throughput metric — track trend, not absolute value
    Compilations/sec vs Batch Requests/sec High ratio = excessive recompiling, often ad-hoc query bloat (Module 1)
    Lock Waits/sec Rising trend = growing blocking problem (Module 5)
    Full Scans/sec Rising trend alongside stable workload = missing/degraded indexes (Module 2)

    The Complete DMV Reference From This Course

    sys.dm_os_buffer_descriptorsBuffer pool contents (M1) sys.dm_exec_cached_plansPlan cache contents (M1) sys.dm_db_missing_index_detailsIndex candidates (M2) sys.dm_db_index_usage_statsIndex read/write balance (M2) sys.dm_exec_query_statsHistorical query cost (M3/M4) sys.dm_os_waiting_tasksLive blocking/latch state (M5)

    The Right Habit: One Dashboard, Not Twenty Tools

    Query Store, Extended Events, DMVs, and PerfMon aren’t competing tools — they answer different question shapes. PerfMon: is there a trend problem over time? DMVs: what’s the current/historical state right now? Extended Events: capture specific events as they happen. Query Store: how has this specific query’s performance evolved? Combine them per the Evidence-First workflow rather than reaching for just one out of habit.


    Enjoyed this?

    Subscribe to get every new lesson as soon as it’s published, and share it with a developer who’d find it useful.

    📡 Subscribe via RSS  | 
    Share on X  | 
    Share on LinkedIn  | 
    Share on Facebook

    Want the full structured course with quizzes and hands-on labs? Check out SQL Server Performance Tuning, coming soon on this site.