SQL Server: No New Index. No Schema Changes. 10x Faster Queries – SQL Server Batch Mode on Rowstore Deep Dive!! Part 4!

Hi guys, welcome to Part 4!!

I hope you are enjoying this series. I truly believe it can be very useful for those who use SQL Server professionally as I have been doing for more than 20 years (how time flies!).

Today we will talk about Batch Mode on Rowstore and how to make your Query run 10x Faster Without Adding Any Index

Well...in Part 3 we introduced Columnstore indexes and saw how Batch Mode execution can dramatically improve analytical queries.

If you missed the previous part, you can read it here:

SQL Server Filtered Index vs Indexed View – Complete Performance Comparison

But here’s the twist.

Starting with SQL Server 2019, you don’t always need a Columnstore index to get Batch Mode performance.

SQL Server can activate Batch Mode on Rowstore.

And sometimes… as i told you at the start of this post ....your query becomes 5x or 10x faster without adding a single index. So i suggest you to continue to read...


What Is Batch Mode?

Traditionally, SQL Server processes queries in Row Mode. That means:

  • One row at a time
  • One operator call per row
  • High CPU overhead for large datasets

Batch Mode changes the execution model.

  • Processes rows in batches (typically up to 900 rows per batch)
  • Uses vectorized processing
  • Reduces CPU cycles per row
  • Improves aggregation and join performance dramatically

Instead of calling operators millions of times, SQL Server processes chunks of rows in a single CPU-efficient operation.


Row Mode vs Batch Mode – The Real Difference

Feature Row Mode Batch Mode
Processing Unit 1 row Up to ~900 rows
CPU Efficiency Lower Much Higher
Aggregation Speed Moderate Very Fast
Memory Usage Standard Optimized

Batch Mode is not just faster. It changes how operators internally execute.


When Does SQL Server Activate Batch Mode on Rowstore?

Batch Mode on Rowstore is available starting from:

  • SQL Server 2019
  • Database compatibility level 150

To enable it:


ALTER DATABASE YourDatabase
SET COMPATIBILITY_LEVEL = 150;

SQL Server may automatically choose Batch Mode if:

  • The query is analytical (GROUP BY, aggregates, joins)
  • Large number of rows involved
  • Estimated cost justifies vectorization

No Columnstore index required.


Demo – Row Mode vs Batch Mode

Let’s test a large aggregation:


SELECT CustomerID,
       SUM(Amount) AS TotalAmount
FROM dbo.Sales
GROUP BY CustomerID;

Step 1 – Compatibility Level 140 (SQL Server 2017 behavior)


ALTER DATABASE YourDatabase
SET COMPATIBILITY_LEVEL = 140;

Execution Plan:

  • Hash Aggregate
  • Row Mode
  • High CPU consumption

Step 2 – Compatibility Level 150


ALTER DATABASE YourDatabase
SET COMPATIBILITY_LEVEL = 150;

Execution Plan now shows:

  • Hash Aggregate (Batch Mode)
  • Vectorized execution
  • Lower CPU cost

Performance Comparison

Compatibility Level Execution Mode CPU (ms) Elapsed (ms)
140 Row Mode 1200 1500
150 Batch Mode 220 320

Same query. Same indexes. Same data.

Completely different execution engine behavior.


Memory Grant Feedback

SQL Server 2019 also improves memory management using Memory Grant Feedback.

If the first execution:

  • Overestimates memory → wastes resources
  • Underestimates memory → spills to tempdb

SQL Server adjusts the memory grant for subsequent executions.

Combined with Batch Mode, this creates:

  • More stable performance
  • Fewer spills
  • Better concurrency

Adaptive Joins

Another intelligent feature introduced in modern versions is Adaptive Joins.

Instead of choosing Nested Loop or Hash Join at compile time, SQL Server can decide at runtime based on actual row counts.

This reduces the risk of:

  • Bad cardinality estimates
  • Parameter sniffing side effects
  • Plan instability

Batch Mode works extremely well together with Adaptive Joins.


Why This Matters

Until SQL Server 2017, getting Batch Mode required Columnstore.

From SQL Server 2019 onward, you may gain analytical acceleration without changing your schema.

That means:

  • No additional index maintenance
  • No extra storage
  • No schema redesign

Sometimes performance is not about adding objects.

It’s about enabling the right execution model.


Final Thoughts

Filtered Index reduces I/O.

Indexed View removes aggregation cost.

Columnstore changes the storage engine.

Batch Mode on Rowstore changes the execution engine.

And that is a completely different level of optimization.

In performance tuning, the biggest gains often come not from adding more indexes, but from understanding how SQL Server really executes your queries.

See you in Part 5 😉

Comments

I Post più popolari

Speaking to Sql Server, sniffing the TDS protocol

SQL Server, find text in a Trigger, Stored Procedures, View and Function. Two ways and what ways is better

SQL Server, Avoid that damn Table Spool!