If for whatever reason you are unable to get batch mode to run as quickly as row mode, the weapon of last resort is to disable batch mode altogether.
Previous posts in this series:
Now onto ways to disable batch mode:
- Lowering the database compatibility level: batch mode was introduced with different SQL Server versions depending on if you’re using columnstore indexes or rowstore indexes. Lowering the database compatibility level will disable also disable batch mode, along with many other features and enhancements, including the cardinality estimator. I would generally not recommend this route; there are finer grained knobs that can be tweaked.
- Database-scoped configuration: BATCH_MODE_ON_ROWSTORE. Only disables batch mode on rowstore indexes
- Query hint: USE HINT(‘DISALLOW_BATCH_MODE’). Disables batch mode altogether (both row and columnstore indexes)
- Modifying table/query in such a way that it prevents batch mode from occurring. Why would you want this? In some cases, we don’t have direct control over the final query that is executed (i.e. views, SSAS queries, or any framework that wraps your base query in a subquery/cte). In these scenarios, query-level hints can’t be used.
As of SQL2022, MS documentation mentions a few limitations in batch mode, and this became my inspiration for finding another way to force row mode. Specifically, converting an existing an existing column to a LOB type such as nvarchar(max) will force row mode; beware this can have memory grant or un-sargability implications.
(it’s quite interesting that this is yet another reason why you want to avoid using varchar/nvarchar(max); this prevents batch mode, which you generally want)
























