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

Operational Analytics, Hybrid Workloads, Resource Isolation, and When to Use a Warehouse

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

Advanced185–240 minutesHTAP architecture decision labSQL Server 2025 CU7 · 17.0.4065.4NCCI core: Express/Developer · Resource Governor: Standard+Single-instance mandatory path · Last reviewed August 2026

Learning outcomes

ServiceHub wants dashboards that are seconds old, but the same database handles dispatch writes, technician assignment and customer status changes. Adding a nonclustered columnstore can make analytics much cheaper than repeated rowstore scans, yet it also adds write maintenance, memory/CPU demand and concurrency competition. Hybrid Transactional/Analytical Processing (HTAP) is therefore an operating model, not merely “create NCCI.” This lesson builds acceptance criteria for co-locating analytics and for deciding when a dedicated warehouse/lakehouse is the safer architecture.

01

Design a rowstore + NCCI operational-analytics pattern and measure both analytical reads and write-maintenance cost.

02

Use Query Store/DMVs and local workload observations instead of vendor-style benchmark promises.

03

Explain SQL Server 2025 Resource Governor availability and when workload isolation can reduce analytical interference.

04

Use readable secondaries only with explicit staleness, routing, licensing and redo-lag assumptions.

05

Define concrete exit criteria for moving analytical work to a warehouse/lakehouse or replicated reporting store.

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. HTAP begins with a shared consistency requirement

Operational analytics is attractive when users need current transactional state and the analytical query can safely share the OLTP engine. NCCI lets the base rowstore preserve transactional indexes while a columnstore copy serves wide scans. The data is transactionally maintained with the base table, so the analytical representation is not an asynchronously replicated cache. That consistency benefit must be weighed against extra storage, log volume and write CPU.

sql · compare an analytical aggregate with the NCCI present
SET STATISTICS IO ON;SET STATISTICS TIME ON;GOSELECT region_code,status,       COUNT_BIG(*) AS orders,       SUM(labor_minutes) AS labor_minutes,       SUM(amount) AS amountFROM lab19.LiveWorkOrderWHERE opened_at >= '2026-03-01'GROUP BY region_code,statusORDER BY region_code,status;GOSET STATISTICS IO OFF;SET STATISTICS TIME OFF;GO

Capture the actual plan, segment IO and elapsed/CPU on your own machine. Then record the same query after disabling the NCCI in a disposable test only, or use an isolated clone, to quantify whether the index changes the plan/work materially. Do not publish a single laptop timing as a universal speedup.

2. Every analytical copy creates a write tax

An NCCI must be maintained as base rows are inserted, updated and deleted. Frequent status/labor/amount changes affect the analytical index columns and can create delta/delete pressure. The correct question is not “does the dashboard run faster?” but “does dashboard benefit exceed additional write latency, log, storage, memory and maintenance under peak transactional concurrency?”

sql · capture before/after write evidence locally
-- Run in a disposable test window and compare with your own baseline.DECLARE @start datetime2(3)=SYSUTCDATETIME();BEGIN TRAN;UPDATE lab19.LiveWorkOrderSET labor_minutes=labor_minutes+1,    amount=amount+0.50WHERE work_order_id BETWEEN 2005000 AND 2014999;COMMIT;SELECT DATEDIFF(millisecond,@start,SYSUTCDATETIME()) AS local_elapsed_ms;GOSELECT row_group_id,state_desc,total_rows,deleted_rows,trim_reason_descFROM sys.dm_db_column_store_row_group_physical_statsWHERE object_id=OBJECT_ID(N'lab19.LiveWorkOrder')ORDER BY row_group_id;GO

The elapsed value is explicitly a local observation. Repeat under representative concurrency/cache/storage conditions, capture transaction-log growth and waits, and compare against the same workload in a controlled clone without the NCCI. One test run cannot establish causation or production capacity.

3. Resource isolation can protect OLTP, but it cannot create capacity

Resource Governor classifies incoming sessions into workload groups/resource pools and can govern CPU/memory and related resources. SQL Server 2025 makes Resource Governor available in Standard and Standard Developer as well as Enterprise; Express remains unsupported. This widens the ability to isolate reporting sessions in Standard production, but governance only allocates finite resources—it does not make an overloaded server large enough.

sql · inspect Resource Governor capability/state without changing production configuration
SELECT CAST(SERVERPROPERTY('Edition') AS nvarchar(128)) AS edition,       CAST(SERVERPROPERTY('ProductVersion') AS nvarchar(128)) AS product_version;SELECT is_enabled FROM sys.resource_governor_configuration;SELECT pool_id,name,min_cpu_percent,max_cpu_percent,       min_memory_percent,max_memory_percentFROM sys.resource_governor_resource_pools;SELECT group_id,name,pool_id,importance,request_max_memory_grant_percentFROM sys.resource_governor_workload_groups;GO

The mandatory lab is inspection-only because a classifier/resource-pool change affects instance-wide workload admission. In a dedicated test instance, you can classify reporting logins/application names into a constrained group, then validate both OLTP latency and dashboard SLA before adopting it.

4. Readable secondaries move reads, but also change consistency/operability

An Enterprise Availability Group readable secondary can offload analytical reads, but Chapter 16 established the boundaries: secondary data can lag while redo catches up, read-only routing requires a listener/routing list and ApplicationIntent=ReadOnly, and a readable secondary is not a zero-lag cache. Standard Basic AG does not provide readable-secondary scale-out. If your dashboard requires read-your-own-write semantics immediately after a transaction, routing it to an asynchronous secondary can violate the product requirement even if the query is fast.

Placement Freshness OLTP interference Operational burden
Same rowstore + NCCI Transactional/current Shared CPU/memory/write maintenance Columnstore health and workload governance
Readable AG secondary Redo-lag dependent Read CPU moved; primary still sends log Enterprise AG, routing, redo/lag monitoring, failover semantics
Warehouse/lakehouse Pipeline/stream lag dependent Heavy analytics isolated ETL/CDC/streaming, schema ownership, reconciliation, extra platform

5. Define the warehouse/lakehouse exit criteria before the incident

A dedicated analytical system becomes compelling when the analytical data model diverges from OLTP, retention greatly exceeds operational needs, joins span multiple source systems, scans compete persistently with customer transactions, report SLAs require independent scaling, or transformation/history semantics require a curated fact/dimension/lake model. Moving analytics also creates new contracts: change capture, replay, retention, schema evolution and reconciliation from Chapter 18 become first-class.

sql · record an explicit architecture decision instead of a vague tuning preference
DROP TABLE IF EXISTS lab19.AnalyticsDecision;GOCREATE TABLE lab19.AnalyticsDecision(  decision_id int IDENTITY PRIMARY KEY,  criterion varchar(80) NOT NULL,  observed_value nvarchar(200) NOT NULL,  threshold_or_requirement nvarchar(200) NOT NULL,  disposition varchar(40) NOT NULL,  recorded_at datetime2(3) NOT NULL DEFAULT SYSUTCDATETIME());INSERT lab19.AnalyticsDecision(criterion,observed_value,threshold_or_requirement,disposition)VALUES('freshness','dashboard requires current committed status','< 5 seconds','keep candidate on primary/NCCI'),('cross-source joins','none today','if CRM + telemetry joins become mandatory','warehouse trigger'),('OLTP interference','must be measured under peak load','p95 dispatch SLA cannot regress','test before rollout'),('retention','12 months operational','multi-year curated history','warehouse trigger');SELECT * FROM lab19.AnalyticsDecision ORDER BY decision_id;GO

The example values are architectural placeholders to demonstrate a decision register, not measurements of your production system. Replace them with measured latency/resource evidence and business requirements. A clear exit criterion prevents the team from trying to “tune harder” after the shared engine is already a bottleneck.

Wrong approach. “Columnstore made one dashboard fast, so put every BI query on the OLTP primary.” That ignores concurrency, resource grants, scan spill/tempdb, NCCI write tax, data-model divergence and failure domains. Repair by defining freshness and isolation requirements first, then validating the least complex architecture that satisfies them.

6. Chapter cleanup and production checklist

sql · remove only Chapter 19 disposable objects
USE ServiceHubLab;GODROP TABLE IF EXISTS lab19.AnalyticsDecision;DROP TABLE IF EXISTS lab19.LiveWorkOrder;DROP TABLE IF EXISTS lab19.WorkOrderFact;GOIF SCHEMA_ID(N'lab19') IS NOT NULLAND NOT EXISTS(  SELECT 1 FROM sys.objects WHERE schema_id=SCHEMA_ID(N'lab19'))  DROP SCHEMA lab19;GO

The cleanup does not touch the established ops course schema, Query Store, HA settings, Resource Governor, or instance configuration. Production adoption should record engine build/edition, compatibility level, dataset and rowgroup profile, query mix, write rate, peak concurrency, MAXDOP, memory, Query Store baseline, storage/tempdb behavior, maintenance plan, rollback and the criteria that would trigger migration to a separate analytical platform.

7. Production judgment and bridge

Keep analytics on the transactional system only when freshness, consistency and operational simplicity outweigh the resource coupling and you can prove transactional SLAs remain healthy. Use NCCI/ordered NCCI, workload governance and readable secondaries as tools with explicit boundaries—not as excuses to keep unlimited BI beside OLTP. Chapter 20 moves to another specialized engine: In-Memory OLTP, where memory-optimized tables, checkpoint files and optimistic concurrency require an entirely different durability/index model from “ordinary tables cached in RAM.”

Check your understanding

  1. What is the core benefit of NCCI for operational analytics?
  2. What must be measured besides dashboard query speed?
  3. What changed for Resource Governor in SQL Server 2025?
  4. Why is a readable AG secondary not equivalent to the primary for freshness?
  5. Name two triggers for moving analytics to a warehouse/lakehouse.
Review the answers

1. It keeps the OLTP rowstore as primary while maintaining a columnstore representation for analytical scans over selected columns.

2. OLTP write latency, log/storage overhead, rowgroup health, CPU/memory/grants, concurrency and maintenance cost.

3. It is now available in Standard/Standard Developer as well as Enterprise; Express remains unsupported.

4. Redo can lag, and routing/failover semantics mean reads may observe an older committed state.

5. Examples include persistent OLTP interference, multi-source/curated modeling, independent scale/SLA needs, or long historical retention beyond operational requirements.

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.