10.4 Compute/Storage Scaling and Intelligent Query Processing
Key Takeaways
- Vertical scaling changes one database or instance's compute/storage; horizontal scaling adds replicas or pools; Hyperscale vCore scaling is constant-time regardless of database size.
- Hyperscale named replicas provide independently-sized read-scale without affecting the primary and without a tier migration.
- IQP features are gated by database compatibility level, not engine version; level 110 disables all IQP from 130/140 onward even on SQL Server 2022.
- Key IQP features: adaptive join, batch mode on rowstore, memory grant feedback (batch and row mode), table variable deferred compilation, scalar UDF inlining, parameter sensitive plan optimization.
- Post-upgrade process: keep compat level, enable Query Store, baseline, raise compat level one step at a time, use plan forcing for regressions.
Why Scaling and IQP Matter
Two of the most testable topics in Domain 3 are scaling (the levers you pull when a database outgrows its current compute or storage) and Intelligent Query Processing (IQP) — a family of optimizer improvements Microsoft ships in waves, gated by database compatibility level. Chapter 3 covers the platform-specific scaling mechanics in depth; here we summarize the scaling levers and focus on IQP, which is unique to this chapter.
Scaling Recap
| Platform | Vertical scale | Horizontal scale | Notes |
|---|---|---|---|
| Azure SQL Database | DTU or vCore size (e.g. GP_Gen5_4 to GP_Gen5_8); online with brief switchover | Read replicas (Business Critical, Premium); named replicas (Hyperscale); elastic pools | Moving into/out of Hyperscale is a migration, not an in-place tier change |
| SQL Managed Instance | vCores (4–80), storage, hardware generation | Instance pools (2-vCore instances); readable secondary on Business Critical | Tier change (GP to BC) is size-of-data; vCore/storage change ends in brief failover |
| SQL Server on Azure VMs | Resize VM (memory-optimized E-series); disk types (Premium SSD, Premium SSD v2, Ultra Disk) | Always On AGs, readable secondaries | Watch the VM-level IOPS ceiling; stripe disks; tempdb on D: |
Vertical scaling changes compute or storage capacity for a single database or instance; horizontal scaling adds replicas or pools. The decision pattern: if a workload saturates the primary, scale up; if it saturates only for reads or for a specific tenant, scale out.
Azure SQL Database Elastic Pools and Database Moves
Moving a database into an elastic pool (ALTER DATABASE ... MODIFY (SERVICE_OBJECTIVE = ElasticPool)) and out again is an online operation. Changing a database's service objective (DTU size or vCore size) is online with a brief connection drop at switchover. Changing between General Purpose and Business Critical is also online but involves data movement (size-of-data). On Hyperscale, scaling vCores is a constant-time metadata operation, because compute is decoupled from the page servers holding data — you can scale from 2 to 80 vCores in minutes regardless of database size, and you can add up to four named replicas for read scale-out.
An Azure SQL Database in the Hyperscale tier needs more read-scale capacity for analytical queries without affecting the primary OLTP workload. What is the fastest, most isolated operation?
Intelligent Query Processing (IQP)
Intelligent Query Processing is a family of query optimizer and execution improvements introduced in waves starting with SQL Server 2017 (compatibility level 140) and continuing through SQL Server 2022 (level 160). IQP features are gated by database compatibility level, not engine version — running SQL Server 2022 with a database at compatibility level 110 disables most IQP features even though the engine is new. This is the most common exam trap in this area.
The IQP family, by the compatibility level that introduced each:
| Feature | Compat level | Benefit |
|---|---|---|
| Adaptive join (batch mode) | 140 | Defers the choice of hash vs loop join until runtime, after the first input is scanned |
| Memory grant feedback (batch mode) | 140 | Adjusts the memory grant on subsequent executions of a cached plan to avoid spills or over-grants |
| Adaptive memory grant feedback (row mode) | 150 | Extends memory grant feedback to row-mode plans |
| Batch mode on rowstore | 150 | Applies batch-mode execution to rowstore indexes, accelerating scan-heavy plans |
| Table variable deferred compilation | 150 | Defers cardinality estimation of table variables until after the first iteration, improving plans |
| Parameter sensitive plan optimization | 150 (SQL Server 2022) | Generates multiple plans for the same query based on parameter value distribution |
| Scalar UDF inlining | 150 | Inlines simple scalar UDFs into the query, removing the per-row function call overhead |
Approximate count distinct (APPROX_COUNT_DISTINCT) | 150 | Returns an approximate count using HyperLogLog, faster and lower-memory for huge distinct sets |
| Row mode memory grant feedback | 150 | Memory grant feedback for row-mode plans |
| Disk spilling improvements (batch sort feedback) | 150/160 | Better sort spill behavior with feedback-driven memory adjustments |
Each feature is designed to fix a class of plan-quality problem the optimizer previously could not: adaptive joins fix bad plan choices based on stale cardinality; memory grant feedback fixes spill-heavy or memory-wasting plans; batch mode on rowstore brings columnar-engine speed to rowstore tables without requiring a columnstore index.
IQP Feature Deep Dive
A few features deserve attention because they appear in scenario questions:
- Adaptive join: the optimizer builds both a hash-join index and prepares a nested-loop path; at runtime, after scanning the build input, it picks the cheaper path. Use it for cases where row counts vary widely between executions. The tradeoff: adaptive joins use more memory than a static plan.
- Memory grant feedback: on the second execution of a plan, the engine checks whether the first execution spilled or wasted memory and adjusts the grant. It can fix plans that consistently spill to tempdb because of over-estimation. Row-mode feedback extends this beyond the original batch-mode scope.
- Batch mode on rowstore: lets a query against a rowstore index use batch-mode operators. The engine can apply batch-mode operators to rowstore scans without requiring a columnstore index on the table, accelerating scan-heavy reporting workloads.
- Scalar UDF inlining: turns a T-SQL scalar function into an inline expression, eliminating the row-by-row context switch. Not all UDFs are inlinable — ones with side effects, non-deterministic calls, or certain constructs remain non-inlined.
- Parameter sensitive plan optimization (PSPO): solves the "parameter sniffing on steroids" problem where the same plan is good for one parameter value and catastrophic for another. The optimizer can now keep multiple plans and dispatch based on parameter value ranges. This is the post-upgrade answer when parameter sniffing regresses a workload.
- Approximate count distinct: returns a count of distinct values using HyperLogLog with a small error margin, dramatically faster and lower-memory than
COUNT(DISTINCT ...)for billion-row distinct sets. Ideal for dashboards where an exact count is not required.
Compatibility Level Gating
The hard rule: IQP features are enabled by database compatibility level, not engine version. A database at compatibility level 110 (SQL Server 2012) running on SQL Server 2022 disables all IQP features from 130/140 onward. The recommended post-upgrade process:
- Upgrade the engine, keep the database compatibility level at its prior value.
- Enable Query Store (
ALTER DATABASE ... SET QUERY_STORE = ON). - Wait for a baseline of workload data (Microsoft suggests at least a full business cycle).
- Raise the compatibility level one step at a time (110 to 130 to 140 to 150 to 160), watching Query Store for regressions at each step.
- If a query regresses at a new level, use Query Store plan forcing to keep the prior plan, or disable a specific IQP feature via a
QUERY_HINTor database-scoped configuration likeLEGACY_CARDINALITY_ESTIMATION = ON.
ALTER DATABASE SCOPED CONFIGURATION provides escape hatches — for example, you can run at compatibility level 150 (for most IQP features) but turn off QUERY_OPTIMIZER_HOTFIXES or set LEGACY_CARDINALITY_ESTIMATION = ON if a specific workload regresses. The Data Migration Assistant (DMA) and Query Store's regressed-queries report are the tools to validate each step.
A database migrated from SQL Server 2014 to SQL Server 2022 still has database compatibility level 110. Which IQP features are enabled?