Optimizing Read‑Heavy Workloads in Azure SQL Database with Read‑Scale‑Out
Learn how to offload read traffic in Azure SQL Database Premium and Business Critical tiers with Read‑Scale‑Out, verify routing, monitor replication lag, and understand the key trade‑offs.
10 Jul 2025, 02:02 UTC

Problem: CPU & I/O Contention on a Single Node
In many applications the same Azure SQL Database instance handles both transactional writes and heavy analytical queries. Even with vertical scaling, a large SELECT can spike CPU and I/O on the primary node, pushing latency for write‑intensive users. The classic resource contention problem is that the primary must honor ACID while also scanning large tables.
How Read‑Scale‑Out Works
Premium and Business Critical tiers maintain an internal read‑only replica that is normally used only for fail‑over. Read‑Scale‑Out allows an application to target that replica for read‑only traffic, effectively giving you a second compute engine for SELECTs without provisioning a separate database. The replica is kept up‑to‑date by an asynchronous replication that typically lags only a few milliseconds, but it can be higher under heavy write loads.
The replica shares the same physical infrastructure as the primary, but the read workload is isolated so that write traffic on the primary is not affected.
Enabling the Feature
There is no portal switch or Azure CLI command to enable Read‑Scale‑Out; the service tier automatically provides the replica. The only step is to tell the engine which connection should go to the replica. Add ApplicationIntent=ReadOnly to the connection string.
Server=tcp:yourserver.database.azure.com,1433;Initial Catalog=YourDB;ApplicationIntent=ReadOnly;User ID=youruser;Password=yourpassword;Encrypt=true;TrustServerCertificate=false;Connection Timeout=30;
Replace yourserver, YourDB, youruser, and yourpassword with your own values. The connection string is used by drivers such as ADO.NET, JDBC, or ODBC. No special permissions are required beyond normal SELECT rights.
Verifying Routing to the Replica
Because the logical server name is the same for both primary and replica, SELECT @@SERVERNAME is not a reliable indicator. A more robust check uses the session’s connection properties:
- Open two separate connections: one with the default intent (read/write) and one with
ApplicationIntent=ReadOnly. - On each connection, run:
SELECT @@SPID AS SessionId, SERVERPROPERTY('MachineName') AS MachineName; - On the read‑only connection, run:
The result will include a column namedSELECT * FROM sys.dm_exec_connections WHERE session_id = @@SPID;application_intent(in newer driver versions) that will showREADONLY. If the column is missing or showsREADWRITE, the intent was not honored.
Alternatively, you can query the Azure portal’s metrics for SQL Database Read‑Scale‑Out Latency to confirm that traffic is being routed to the replica.
Monitoring Replication Lag
In‑region read‑scale‑out does not expose a geo‑replication DMV, but you can use the DMV that reports replication wait times:
SELECT * FROM sys.dm_database_replication_wait;
The column wait_time_ms indicates the average time the replica lags behind the primary. A value above a few milliseconds may indicate that the write workload is saturating the replication channel. For cross‑region geo‑replication, use sys.dm_geo_replication_link_status instead.
Trade‑Offs and Limitations
- Read‑Only Enforcement: Any DML or DDL statement executed on the read‑only connection will return an error.
- Consistency Model: The replica is asynchronously updated, so a read immediately after a write may return stale data. Do not use read‑scale‑out for "read‑your‑own‑writes" scenarios.
- Service Tier Restriction: Read‑Scale‑Out is available only in Premium and Business Critical tiers. It is not supported in General Purpose or Standard tiers.
- No Distributed Transactions: Connections to the read‑only replica cannot participate in distributed transactions.
Practical Checklist
- Confirm your database is in the Premium or Business Critical tier. You can check this in the Azure portal or run:
SELECT name, service_objective FROM sys.databases WHERE name = 'YourDB'; - Identify the application modules that run heavy SELECTs (reporting services, read‑only APIs, analytics dashboards).
- Update their connection strings to include
ApplicationIntent=ReadOnly. - Deploy the changes and run the routing verification steps above.
- During peak load, monitor
sys.dm_database_replication_waitand the Azure Monitor metric Read‑Scale‑Out Latency to ensure replication lag stays within acceptable bounds. - If lag spikes, consider scaling the database to a higher vCore count or moving the write‑heavy workload to a separate database.
Conclusion
Read‑Scale‑Out gives you a built‑in, low‑cost way to offload read traffic from a write‑heavy Azure SQL Database. By simply adding ApplicationIntent=ReadOnly to the connection string, you can double the effective compute for SELECTs while keeping the same database instance. Remember the asynchronous nature of the replica, the service‑tier limitation, and the inability to run DML or distributed transactions on the read‑only node. With the verification steps and monitoring described above, you can confidently deploy read‑scale‑out and observe measurable reductions in CPU and I/O pressure on your primary node.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.