Chapter 19 · Columnstore, Batch Mode, Analytics, and Hybrid Transactional/Analytical Workloads

Batch Mode Processing, Aggregate Pushdown, Segment Elimination, and Plan Reading

Choose deliberately among AGs, replication, log shipping, CDC/ETL and application replication from the information and failover contract actually required.

Advanced175–225 minutesbatch-mode plan-reading labSQL Server 2025 CU7 · 17.0.4065.4Compatibility 170 · edition behavior recordedSSMS 22.8.2 · Last reviewed August 2026

Learning outcomes

Columnstore changes storage, but SQL Server can also change how operators consume rows. Batch mode processes groups of rows through vectorized operators instead of invoking row-mode logic one row at a time. A columnstore scan is a common gateway into batch mode, yet SQL Server 2019+ can also choose batch mode on rowstore at compatibility level 150+. This matters because “batch mode” and “columnstore” are related but not identical concepts. A good plan review separates execution mode, segment elimination, predicate/aggregate pushdown and cardinality/memory behavior.

01

Read actual execution plans for Actual/Estimated Execution Mode instead of assuming columnstore means every operator runs in batch mode.

02

Distinguish batch mode on columnstore from Batch Mode on Rowstore and state the compatibility/configuration prerequisites.

03

Explain aggregate and string predicate pushdown and their current SQL Server 2025 Enterprise scalability boundary.

04

Measure segment elimination with SET STATISTICS IO and connect it to ordered data rather than to batch mode itself.

05

Diagnose spills, memory grants or row-mode islands without attributing every performance change to one plan label.

Lab baseline. SQL Server 2025 (17.x), CU7 build 17.0.4065.4; database compatibility level 170 unless stated otherwise. Columnstore itself is available in Enterprise, Standard, and Express, so the core labs remain free/local. Enterprise Developer is used only when an Enterprise-only behavior such as online index create/rebuild or Enterprise columnstore scalability enhancements must be demonstrated. SQL Server 2025 Standard/Standard Developer also includes Resource Governor; Express does not. SSMS 22.8.2, VS Code + the current MSSQL extension, or current sqlcmd are supported paths. Azure Data Studio is retired.

1. Batch mode changes the execution unit

Row mode passes one row at a time between operators. Batch mode passes vectors/batches of rows, allowing operators to amortize function-call overhead and use CPU-efficient processing for scans, joins, filters, sorts and aggregates when the optimizer chooses it. Columnstore was the original major use case, but Batch Mode on Rowstore (BMOR) can consider batch execution for sufficiently large rowstore queries beginning with SQL Server 2019 at database compatibility level 150 or higher.

The optimizer still chooses the plan. BATCH_MODE_ON_ROWSTORE = ON does not force every rowstore query into batch mode; heuristics consider table size, estimated rows and candidate operators. Likewise, a query touching columnstore can contain row-mode operators where a particular operator or feature does not support batch execution.

sql · verify compatibility and Batch Mode on Rowstore configuration
SELECT name,compatibility_levelFROM sys.databases WHERE database_id=DB_ID();SELECT name,value,value_for_secondaryFROM sys.database_scoped_configurationsWHERE name=N'BATCH_MODE_ON_ROWSTORE';GO

2. Read execution mode from the actual plan, then correlate it with work done

Enable the actual execution plan in SSMS/VS Code or use SET STATISTICS XML ON. Remember the Chapter 10 rule: an actual plan executes the query. On the plan operators, inspect estimated and actual execution mode, row counts, memory grant/warnings, and the storage operator chosen. Then compare with STATISTICS IO/TIME. Operator mode is one part of the explanation, not the result itself.

sql · analytical columnstore query for plan-mode inspection
SET STATISTICS IO ON;SET STATISTICS TIME ON;GOSELECT region_code,       status,       COUNT_BIG(*) AS work_orders,       SUM(labor_minutes) AS total_minutes,       SUM(amount) AS total_amountFROM lab19.WorkOrderFactWHERE opened_at >= '2025-05-01'  AND opened_at <  '2025-09-01'GROUP BY region_code,statusORDER BY region_code,status;GOSET STATISTICS IO OFF;SET STATISTICS TIME OFF;GO

On an Enterprise-family build, a plan may show a columnstore scan feeding a batch-mode hash aggregate, with aggregation pushed into the scan when eligibility rules are met. On Standard/Express, the edition matrix limits some Enterprise columnstore scalability enhancements and batch DOP (Standard DOP 2; Express DOP 1). Therefore, do not use an Enterprise Developer lab result to promise identical operator behavior or throughput in Standard/Express production.

3. Pushdown means doing work nearer the scan

Aggregate pushdown can perform eligible MIN, MAX, SUM, COUNT and COUNT(*) work inside the scan, reducing rows flowing to a separate aggregate. String predicate pushdown can evaluate eligible string predicates against dictionaries/encoded values before materializing every row. These are separate from segment elimination. Segment elimination decides which rowgroups need scanning; pushdown reduces work inside the rowgroups that remain.

Microsoft's SQL Server 2025 edition matrix classifies aggregate pushdown, string predicate pushdown and SIMD optimizations as Enterprise scalability enhancements. Teach the mechanism, but verify the actual plan/edition before claiming it is active. A query can still benefit from column elimination, compression, segment elimination and batch processing when a specific pushdown optimization is absent.

sql · compare pushdown-friendly and less-friendly aggregate shapes
-- Eligible shape: simple aggregate over supported numeric types.SELECT region_code,       SUM(amount) AS total_amount,       COUNT_BIG(*) AS rows_seenFROM lab19.WorkOrderFactWHERE status='CLOSED'GROUP BY region_code;GO-- DISTINCT and expressions can change where aggregation occurs.SELECT region_code,       COUNT(DISTINCT technician_code) AS technicians,       SUM(amount * 1.05) AS adjusted_amountFROM lab19.WorkOrderFactWHERE status='CLOSED'GROUP BY region_code;GO

Compare plans; do not infer pushdown from elapsed time. Look for where the aggregate/filter is represented relative to the columnstore scan and use actual row counts to see how much data flows upward.

4. Segment elimination is independent evidence

sql · measure segment reads/skips for ordered date ranges
SET STATISTICS IO ON;GOSELECT COUNT_BIG(*) AS rows_in_window,       SUM(amount) AS amount_in_windowFROM lab19.WorkOrderFactWHERE opened_at >= '2025-07-01'  AND opened_at <  '2025-07-08';GOSELECT COUNT_BIG(*) AS rows_all,       SUM(amount) AS amount_allFROM lab19.WorkOrderFact;GOSET STATISTICS IO OFF;GO

The messages pane can report Segment reads and segment skipped. If a narrow predicate skips many segments, that is elimination evidence. It does not prove batch mode, and batch mode does not prove elimination. Ordered columnstore can improve elimination by reducing overlapping min/max ranges; a fully qualifying predicate naturally cannot skip the same segments.

Wrong approach. “The plan says Batch, therefore the query is tuned.” A batch-mode query can still have a bad cardinality estimate, excessive memory grant, spill, huge scan because the predicate cannot eliminate segments, skewed parallelism, or expensive downstream sort. Repair by reading the entire actual plan and matching it to waits, grants, segment IO and workload concurrency.

5. Rowstore comparison without changing the database globally

For a rowstore table under compatibility 150+, BMOR is considered heuristically. You can use documented query hints to compare allowed/disallowed batch mode during an experiment instead of toggling the whole database in the middle of a shared workload. This lab is an observation exercise; it is not a recommendation to hint production queries permanently.

sql · compare BMOR eligibility on the operational rowstore
SELECT region_code,       status,       COUNT_BIG(*) AS orders,       SUM(amount) AS amountFROM lab19.LiveWorkOrderGROUP BY region_code,statusOPTION (RECOMPILE, USE HINT('ALLOW_BATCH_MODE'));GOSELECT region_code,       status,       COUNT_BIG(*) AS orders,       SUM(amount) AS amountFROM lab19.LiveWorkOrderGROUP BY region_code,statusOPTION (RECOMPILE, USE HINT('DISALLOW_BATCH_MODE'));GO

Inspect actual plans rather than expecting a particular winner. Dataset size, edition DOP, statistics, memory and query shape determine whether BMOR is chosen or helpful. The hints deliberately alter optimizer search behavior and should not be deployed just to make a plan screenshot say “Batch.”

6. Production judgment and bridge

Use execution mode as one diagnostic dimension. Capture actual plans under representative parameters, pair them with STATISTICS IO/TIME, Query Store history and workload waits, and separate storage skipping from vectorized execution. Lesson 4 moves to ingestion and maintenance: how batch size, partitioning, delete pressure, REORGANIZE and REBUILD determine whether healthy columnstore structures remain healthy.

Check your understanding

  1. Does a columnstore index guarantee every operator runs in batch mode?
  2. What is the compatibility prerequisite for Batch Mode on Rowstore?
  3. How is segment elimination different from aggregate pushdown?
  4. Why must edition be recorded when demonstrating pushdown?
  5. What evidence disproves “batch mode means tuned”?
Review the answers

1. No. Execution mode is operator-specific and plan-dependent; inspect the actual plan.

2. Compatibility level 150 or higher; BATCH_MODE_ON_ROWSTORE is ON by default at that scope.

3. Elimination skips whole rowgroups based on segment ranges; aggregate pushdown performs eligible aggregation inside the scan for rowgroups that are read.

4. SQL Server 2025 lists aggregate/string predicate pushdown and SIMD as Enterprise scalability enhancements.

5. Spills, excessive grants, poor estimates, large segment reads, skewed parallelism or expensive downstream operators can all remain in a batch-mode plan.

Authoritative references

Keep knowledge open

Help the academy stay free and grow.

If these tutorials save you time, a small donation supports new lessons, technical review, diagrams, examples, and long-term maintenance.

ETHEthereum / ERC-20 only
0x716c4Ab160C4B66F31a28AE2448BfF68fc3a2ef0

Send only Ethereum or ERC-20 compatible assets to this address.