This domain is worth 20-25% of DP-300, the joint-largest. Questions show a symptom (high CPU, blocking, a plan regression after an upgrade, fragmented indexes) and ask which tool or feature to use first, or what T-SQL or setting fixes it. Know which tool exists on which platform and the standard troubleshooting order.
Monitoring resource activity and performance
Baseline and metric sources
A baseline is a record of normal behaviour (CPU, IO, memory, waits, query durations, connection counts) at known load. Without it, you can’t tell if a number is bad. Capture it over a representative period, store it (Log Analytics, a table, Query Store), and compare after changes such as migration, tier change or upgrade.
| Source | What it gives | Platform |
|---|---|---|
| Azure Monitor metrics | Platform metrics: CPU %, DTU %, data IO %, log IO %, workers %, sessions %, storage %, deadlocks, connections | SQL Database, MI |
| Diagnostic settings | Sends logs/metrics (SQLInsights, QueryStoreRuntimeStatistics, Errors, Deadlocks, Blocks, Timeouts, AutomaticTuning) to Log Analytics, storage, Event Hubs |
SQL Database, MI |
| Database watcher | Managed, near-real-time monitoring into a Data Explorer or Fabric database; dashboards for estate and single resource | SQL Database, MI, SQL Server on VM |
| Query Store | Query text, plans and runtime stats over time | All |
| DMVs / DMFs | Current state, waits, sessions, IO, indexes | All |
| Extended Events | Lightweight event tracing | All |
| Intelligent Insights | AI-based detection of performance degradation with root cause | SQL Database only |
| Performance Monitor (PerfMon), SQL Server counters | OS and SQL counters | VM, on-premises |
| Activity log | Control-plane operations (scale, create, failover) | All Azure |
| Azure SQL Insights | Retired; replaced by database watcher | - |
Metrics to know: CPU percentage (compute pressure), Data IO / Log IO percentage (storage throttling), Workers percentage (request concurrency limit), Sessions percentage, tempdb and Storage percentage. When any approaches 100% in the tier’s limits you either tune queries or scale the tier.
Configure and monitor activity
- Create alert rules on metrics (static or dynamic threshold) with action groups (email, SMS, webhook, Logic App, runbook).
- In SSMS use Activity Monitor (VM/MI), Performance Dashboard, and Query Performance Insight (SQL Database portal) for top CPU, duration and execution count queries, built on Query Store.
- Log Analytics with KQL against diagnostic logs for correlation. A Workbook can show multiple resources.
Database watcher
Database watcher collects detailed performance and configuration data from SQL targets without agents on the database and stores it in an Azure Data Explorer cluster or Real-Time Analytics (Fabric) database. Key facts:
- A watcher has a managed identity, a data store, and a list of targets (SQL Database, elastic pool, MI, or SQL Server on VM through Arc). The identity needs login and permissions on targets and ingestion rights on the store.
- Uses private endpoints if the target or store has no public access.
- Provides estate-wide dashboard (health, resource use) and detailed dashboards (queries, waits, blocking, storage, backups, replicas, configuration) and sample collection for current activity with per-minute granularity.
- Use it for fleet-level near real-time monitoring with long retention and KQL. For classic deep, per-database tuning, Query Store is the tool.
Extended Events (XEvents)
Extended Events is the lightweight tracing system replacing SQL Trace/Profiler (deprecated). Components: session, events, actions, predicates (filters), targets.
- SQL Database/MI sessions are database-scoped (SQL Database) or server-scoped (MI, VM). Targets:
ring_buffer,event_file(in Azure Blob storage for PaaS),event_counter,histogram. - Typical sessions: deadlock graph (
xml_deadlock_report;system_healthalready captures it on VM/MI), slow queries (sql_statement_completedwithdurationpredicate),wait_info,blocked_process_report. - Create in SSMS with the session wizard, or
CREATE EVENT SESSION ... ON DATABASE. View live data in Watch Live Data or read files withsys.fn_xe_file_target_read_file.
Monitoring and optimizing query performance
Query Store
Query Store is a built-in flight recorder for queries: query text, every plan, and aggregated runtime statistics per time interval. It survives restart and failover.
- On by default in Azure SQL Database and MI; off by default for SQL Server 2019 and earlier (on by default for new databases from 2022). Enable on VM:
ALTER DATABASE db SET QUERY_STORE = ON;. - Configure:
OPERATION_MODE = READ_WRITE,QUERY_CAPTURE_MODE(AUTOignores trivial queries;ALLfor baseline),MAX_STORAGE_SIZE_MB,DATA_FLUSH_INTERVAL_SECONDS,INTERVAL_LENGTH_MINUTES,STALE_QUERY_THRESHOLD_DAYS,SIZE_BASED_CLEANUP_MODE. A full store goes READ_ONLY, so monitor its size. Wait statistics capture is available too, and Query Store on readable secondaries is supported on newer builds. - Reports in SSMS: Regressed Queries, Overall Resource Consumption, Top Resource Consuming Queries, Queries With Forced Plans, Queries With High Variation, Tracked Queries, Query Wait Statistics.
- Force plan (
sp_query_store_force_plan) pins a plan when a plan regression occurs, for example after a compatibility-level upgrade. Query Store hints (sp_query_store_set_hints) add query hints without changing code. - Compare before/after using Query Store when upgrading the compatibility level; this is the intended workflow for Query Tuning Assistant.
Blocking and deadlocks
Blocking: one session holds a lock another needs; normal and temporary. Deadlock: circular wait, the engine kills a victim (error 1205). Find blocking:
SELECT r.session_id, r.blocking_session_id, r.wait_type, r.wait_time, t.text
FROM sys.dm_exec_requests r
CROSS APPLY sys.dm_exec_sql_text(r.sql_handle) t
WHERE r.blocking_session_id <> 0;
Follow blocking_session_id to the head blocker (often an open transaction, sys.dm_tran_active_transactions, sys.dm_exec_sessions with open_transaction_count > 0). Resolve by: committing/rolling back, KILL session_id, shortening transactions, adding indexes that reduce scan locks, using Read Committed Snapshot Isolation (RCSI) (default on in Azure SQL Database) or snapshot isolation, and consistent object access order for deadlocks. Accelerated database recovery (ADR) reduces long rollbacks and is on in Azure SQL. Deadlock graphs come from Extended Events or Query Store/diagnostic logs.
DMVs
| DMV / DMF | Use |
|---|---|
sys.dm_exec_requests, sys.dm_exec_sessions, sys.dm_exec_connections |
Running requests, sessions, connections |
sys.dm_exec_query_stats |
Aggregated stats for cached plans (top CPU/IO), since plan cached |
sys.dm_exec_sql_text, sys.dm_exec_query_plan |
Text and plan from handles |
sys.dm_os_wait_stats (server) / sys.dm_db_wait_stats (SQL Database) |
Cumulative waits |
sys.dm_db_resource_stats |
SQL Database resource use in 15-second slices, about 1 hour of history |
sys.resource_stats (in master) |
5-minute, 14-day history |
sys.dm_user_db_resource_governance |
Effective limits for the database |
sys.dm_db_index_usage_stats, sys.dm_db_missing_index_* |
Index use and suggestions |
sys.dm_db_index_physical_stats |
Fragmentation and page density |
sys.dm_exec_requests + sys.dm_tran_locks |
Locks |
sys.dm_io_virtual_file_stats |
File IO latency |
Common waits: PAGEIOLATCH_* (reading data from disk: IO or memory), LCK_M_* (blocking), CXPACKET/CXCONSUMER (parallelism), SOS_SCHEDULER_YIELD (CPU pressure), WRITELOG (log flush, log IO limit), RESOURCE_SEMAPHORE (memory grants), ASYNC_NETWORK_IO (client slow to consume).
Indexes and query shape
- Index types: clustered, nonclustered, covering (
INCLUDEcolumns), filtered, columnstore (analytics), unique, XML, spatial. Rowstore for OLTP, columnstore for scans and aggregation. - Missing index DMVs and the Database Advisor (SQL Database) propose indexes. Validate before creating. Don’t create duplicates. Remove unused/duplicate indexes (
dm_db_index_usage_statsshows no reads) because they slow writes. - Key column order: equality columns first, then range column; put selected extras in
INCLUDE. - Query construct modifications driven by resource use: avoid non-SARGable predicates (functions on columns such as
WHERE YEAR(d)=2026, implicit conversions from mismatched types),SELECT *, scalar UDF in large selects (inlined in 2019+), row-by-row cursors vs set-based, parameter sniffing issues (useOPTION (RECOMPILE),OPTIMIZE FOR, Parameter Sensitive Plan optimization, or Query Store hints),ORtoUNION ALL, andNOT INtoNOT EXISTS. Reduce returned rows and batch large modifications.
Execution plans
Estimated plan (no run) vs actual plan (with row counts) vs live statistics. Look for:
- Scans where seeks were expected, Key Lookups (add covering include), Sort/Hash spills (tempdb warnings, bad memory grants), estimated vs actual row differences (stale statistics, parameter sniffing), thick arrows, parallelism skew, implicit conversion warnings, missing index hints.
- Operators: Index Seek/Scan, Nested Loops (small input), Hash Match (large unsorted), Merge Join (sorted), Stream Aggregate.
- Tools: SSMS plan viewer and Compare Showplan;
SET STATISTICS IO, TIME ON; Query Store plan view;sys.dm_exec_query_plan_stats(last actual plan) withLAST_QUERY_PLAN_STATS.
Intelligent Insights
Intelligent Insights (SQL Database and elastic pools only, not Managed Instance) uses AI over Query Store data to detect performance degradation patterns (reaching resource limits, workload increase, memory pressure, locking, increased MAXDOP, pagelatch contention, missing index, new query, increased wait statistics, tempdb contention, elastic pool DTU shortage, plan regression, database-scoped configuration value change, slow client, pricing tier downgrade) and writes a JSON diagnostics log (the SQLInsights category) with root-cause analysis and recommendations. Send it to Log Analytics, Event Hubs or Storage. Enable via diagnostic settings.
Configuring for optimal performance
Index and statistics maintenance
- Fragmentation thresholds (from
sys.dm_db_index_physical_stats): under 5% nothing; 5-30%REORGANIZE(online, always); over 30%REBUILD(can beONLINE = ON, resumable on PaaS). Only matter for indexes over about 1,000 pages. On SSD storage fragmentation matters far less. Page density also matters. - Statistics drive the optimizer.
AUTO_UPDATE_STATISTICSis on by default;AUTO_UPDATE_STATISTICS_ASYNCavoids blocking queries;UPDATE STATISTICS ... WITH FULLSCANorsp_updatestatsfor refresh after bulk loads; incremental stats on partitioned tables. Rebuild index refreshes the index’s stats with a full scan. - Schedule with SQL Agent (MI, VM), elastic jobs or Azure Automation (SQL Database). Ola Hallengren scripts are a common option.
Integrity checks
DBCC CHECKDB verifies allocation and structural integrity. Azure SQL Database and MI run integrity checks and page-verify automatically, but running DBCC CHECKDB yourself is still allowed. On VMs, schedule it (weekly, on a copy or secondary, or PHYSICAL_ONLY for lighter runs). Page verification is CHECKSUM. Repair options: restore from backup is preferred; REPAIR_ALLOW_DATA_LOSS last resort.
Automatic tuning
| Option | SQL Database | Managed Instance | SQL Server 2017+ |
|---|---|---|---|
| FORCE_LAST_GOOD_PLAN | Yes (default on) | Yes | Yes (needs Query Store) |
| CREATE_INDEX | Yes | No | No |
| DROP_INDEX | Yes | No | No |
The engine detects a regression, forces the last good plan, validates, and reverts if it didn’t help. Index actions are validated and rolled back if performance worsens. Inherit settings from the server or set per database. Check sys.dm_db_tuning_recommendations. Enable on SQL Server with ALTER DATABASE ... SET AUTOMATIC_TUNING (FORCE_LAST_GOOD_PLAN = ON).
Server and database settings
- MAXDOP (max degree of parallelism): on SQL Server, set around cores per NUMA node up to 8. In Azure SQL Database it’s a database-scoped configuration (default 8; set it per database).
- Cost threshold for parallelism (default 5; raise to 25-50 on modern OLTP) on VM/MI.
- Max server memory: leave memory for the OS on VMs.
- Optimize for ad hoc workloads to reduce plan cache bloat. Tempdb: multiple equal-sized data files on VMs.
- Compatibility level controls optimizer behaviour. New databases use the latest; test lower level for legacy apps and raise with Query Store.
Resource Governor
Resource Governor (SQL Server VM, Managed Instance; not SQL Database) limits CPU, memory, and IO per workload. Parts: resource pools (min/max CPU, memory, IOPS), workload groups (importance, request limits, MAXDOP, mapped to a pool), and a classifier function (in master) that routes sessions based on login, app name, host. ALTER RESOURCE GOVERNOR RECONFIGURE applies. Use to stop a reporting user or batch job from starving OLTP. In SQL Database the equivalent is tier/elastic pool limits and workload groups internally governed by the service.
Database-scoped configuration
ALTER DATABASE SCOPED CONFIGURATION SET ... changes behaviours per database, allowing different settings in an elastic pool or per tenant: MAXDOP, LEGACY_CARDINALITY_ESTIMATION, PARAMETER_SNIFFING, QUERY_OPTIMIZER_HOTFIXES, LAST_QUERY_PLAN_STATS, OPTIMIZE_FOR_AD_HOC_WORKLOADS, ELEVATE_ONLINE, ELEVATE_RESUMABLE, ACCELERATED_PLAN_FORCING. It can also be applied to secondaries (FOR SECONDARY). The usual answer for “change MAXDOP/CE for one database only in Azure SQL Database”.
Scale compute and storage
- Database: scale tier/vCores/storage online (DTU → vCore), add read replicas, use serverless for spiky, Hyperscale for storage-growth.
- MI: scale vCores and storage. VM: bigger VM size, more disks, tempdb on local SSD, read-only caching on data disks.
- Know symptoms: CPU 100% = tune queries or scale vCores; log IO % 100% = batch writes, minimal logging, scale; workers % = fix blocking and connection spikes; storage = grow max size or compress; tempdb full = tune sort/spills.
Intelligent query processing (IQP)
IQP features improve performance without code changes, mostly by raising the compatibility level.
| Feature | Compat level | What it does |
|---|---|---|
| Batch mode on rowstore | 150 | Batch processing for analytic queries over rowstore |
| Adaptive joins | 140 (batch mode) | Switch hash/nested loops at runtime |
| Memory grant feedback | 140/150 (row mode 150) | Adjust memory grants across executions; persisted in 160 |
| Table variable deferred compilation | 150 | Better cardinality for table variables |
| Scalar UDF inlining | 150 | Turns scalar UDFs into relational expressions |
| Approximate count distinct | any | APPROX_COUNT_DISTINCT |
| Parameter Sensitive Plan optimization | 160 | Multiple plans for one parameterized query |
| Cardinality estimation feedback / DOP feedback | 160 | Query Store based feedback |
| Optimized plan forcing | 160 | Faster compile for forced plans |
Memory grant feedback fixes spills or oversized grants; PSP fixes parameter sniffing. Use the latest compatibility level for new work and use Query Store to protect against regressions.
Exam checklist
- Metrics: CPU %, Data IO %, Log IO %, Workers %.
sys.dm_db_resource_statsfor 1 hour,sys.resource_statsfor 14 days. - Database watcher for estate-level monitoring into Data Explorer; Intelligent Insights is SQL Database only.
- Extended Events replaced Profiler;
event_fileto Blob; deadlock graph. - Query Store: on by default in Azure SQL; reports; force plan; read-only when full.
- Blocking:
blocking_session_id, head blocker, RCSI. - Reorganize 5-30%, rebuild over 30%; statistics updates;
DBCC CHECKDB. - Automatic tuning: all three on SQL Database, only force plan on MI.
- Resource Governor not in SQL Database; DB-scoped configuration for per-database settings.
- IQP: compat level 150 and 160 features.