Home / Azure

AzureHow-toIntermediate

Optimization: Azure SQL Database sizing with elastic pools, serverless and the right service tier

Single databases provisioned for their peak sit idle most of the day. Measure each database's usage pattern, put databases with non-overlapping peaks into elastic pools, use serverless for intermittent ones, and right-size the service tier and vCores using resource stats, not guesses.

Deepak Bhardwaj4 min read

Applies toAzure SQL Database (DTU and vCore models), elastic pools, General Purpose serverless, Hyperscale

Three usage patterns

Pattern Best fit
Steady load all day Provisioned single database, right-sized
Many databases, each busy at different times Elastic pool
Busy for short periods, idle for hours (dev, internal tools) Serverless (General Purpose), auto-pause where latency on resume is acceptable

1. Measure usage

sys.resource_stats in master keeps about 14 days of 5-minute data per database:

-- run in master of the logical server
SELECT database_name,
       MAX(avg_cpu_percent)       AS max_cpu,
       AVG(avg_cpu_percent)       AS avg_cpu,
       MAX(avg_data_io_percent)   AS max_data_io,
       MAX(avg_log_write_percent) AS max_log_write
FROM sys.resource_stats
WHERE start_time > DATEADD(day, -14, SYSUTCDATETIME())
GROUP BY database_name
ORDER BY max_cpu DESC;

For finer detail inside one database (last hour, 15-second samples): sys.dm_db_resource_stats.

Read it like this: avg < 10% and max < 40% means over-provisioned; max hitting 100% regularly means throttled (see the "Azure SQL Database is slow" post); a gap between avg and max shows how spiky the database is.

2. Elastic pools: size by the peak of the sum

A pool needs enough capacity for the combined load at the busiest moment, not the sum of each database's peak. Build the combined curve from sys.resource_stats (CPU % × the database's vCores, summed per 5-minute slot), take the max, and add headroom (~20%).

Good pool candidates: SaaS tenant databases, departmental apps with office-hours peaks in different time zones, many small databases. Poor candidates: two big databases that peak at the same time.

az sql elastic-pool create -g rg-data -s sql-prod -n pool-apps --edition GeneralPurpose \
  --family Gen5 --capacity 8 --db-max-capacity 4 --db-min-capacity 0
az sql db update -g rg-data -s sql-prod -n appdb17 --elastic-pool pool-apps

Per-database min/max settings stop one tenant from taking the whole pool.

3. Serverless for intermittent databases

az sql db update -g rg-data -s sql-dev -n testdb \
  --edition GeneralPurpose --compute-model Serverless --family Gen5 \
  --min-capacity 0.5 --capacity 4 --auto-pause-delay 60
  • Billed per second for compute used, within min/max vCores; storage billed always.
  • Auto-pause (General Purpose serverless) stops compute billing after the delay; the first connection after a pause waits for resume, so apps need connection retry logic.
  • Some features keep a database from auto-pausing (e.g. geo-replication, long-term retention backups, certain sync/job features). Check the current list.

Hyperscale also offers serverless compute (with different pause behaviour). Check what your tier supports.

4. Right-size provisioned databases

  • Scale vCores to keep p95 CPU in the 40–70% range for steady workloads.
  • Check memory pressure and log write before scaling down. Log rate limits are tied to tier and vCores.
  • Business Critical only where you need its local SSD latency, in-memory OLTP, or built-in read replica; otherwise General Purpose.
  • Scaling causes a brief disconnect at the switch; schedule it.
az sql db update -g rg-data -s sql-prod -n orders --service-objective GP_Gen5_4

5. Other levers

Lever Note
Azure Hybrid Benefit Use existing SQL Server licences with Software Assurance on vCore
Reserved capacity For steady provisioned vCores you're confident about
Read scale-out Offload reporting to replicas where the tier includes them
Query tuning Often the biggest saving: fix the top queries before buying vCores

6. Review regularly

Run the sys.resource_stats query monthly; usage changes as apps change. Tag databases with owner and environment so idle ones can be challenged.

Tip

Before scaling down, look at the max over at least two weeks that include month-end or batch windows. A database idle on Tuesday can be saturated on the 1st.

Checklist

  • 14 days of resource stats per database reviewed
  • Pool candidates grouped by combined peak
  • Serverless for intermittent databases, apps retry on resume
  • Provisioned databases right-sized, tier justified
  • Hybrid Benefit / reservations reviewed
  • Monthly review scheduled