4.3 Database Cost Optimization
Key Takeaways
- Aurora Serverless v2 bills per ACU-second and can now scale to 0 ACUs with automatic pause and resume — ideal for dev/test and intermittent workloads.
- RDS Reserved Instances save up to ~69% (3-year) for steady-state production databases; Graviton instances add ~20% price-performance.
- DynamoDB On-Demand bills per request for unpredictable traffic; Provisioned with auto-scaling (and Reserved Capacity, up to ~77% off) is cheaper when predictable.
- Read replicas scale reads out onto cheaper instances and can let you downsize the primary; Aurora supports up to 15 replicas with auto load balancing.
- ElastiCache and DynamoDB DAX cut expensive repeated reads, lowering required IOPS/RCU and letting you run a smaller, cheaper database.
RDS Cost Optimization
Right-size before committing. Use Performance Insights to find true CPU/memory/IO usage, CloudWatch for freeable memory and IOPS, and Compute Optimizer for recommendations. Switching to Graviton (arm64) RDS instances typically yields ~20% better price-performance with no schema change.
| RDS pricing option | Savings | Commitment |
|---|---|---|
| On-Demand | baseline | none |
| Reserved, 1-year | ~40% | 1 year |
| Reserved, 3-year | up to ~69% | 3 years |
| Aurora Serverless v2 | pay per ACU-second | none |
Read replicas scale reads horizontally onto smaller instances and offload the primary so you can sometimes downsize it. Aurora supports up to 15 read replicas with automatic load balancing via the reader endpoint. A stop/start schedule also zeroes compute charges for non-production RDS (a stopped instance still bills storage and auto-restarts after 7 days).
Aurora Serverless v2 — Now Scales to Zero
Aurora Serverless v2 measures capacity in Aurora Capacity Units (ACUs) — each ~2 GiB RAM plus CPU/network. It bills per ACU-second, scaling smoothly between a configured min and max. The minimum can be set as low as 0.5 ACU, and — since late 2024 — to 0 ACUs, where the instance automatically pauses after an inactivity window and resumes on the first new connection. While paused you pay nothing for compute (storage still bills).
| Workload | Provisioned Aurora | Serverless v2 |
|---|---|---|
| Dev/test, ~8 hr/day | ~$730/mo (r6g.large 24/7) | far less; pauses to 0 ACU off-hours |
| Variable, peaks 4x baseline | ~$1,460/mo (sized for peak) | ~$500/mo (scales dynamically) |
| Steady 24/7 high load | ~$730/mo | ~$800/mo (per-ACU overhead) |
Key insight: Serverless v2 wins for variable or intermittent loads; for flat 24/7 load, a provisioned instance on a Reserved Instance is cheaper.
DynamoDB Cost Optimization
| Mode | Pricing (us-east-1) | Best for |
|---|---|---|
| On-Demand | $1.25/M writes, $0.25/M reads | Spiky/unknown traffic |
| Provisioned | $0.00065/WCU-hr, $0.00013/RCU-hr | Steady, predictable |
| Provisioned + Reserved | up to ~77% off provisioned | Long-term steady |
Save more with: TTL to auto-expire items free, DAX to cache hot reads and cut RCU, smaller item sizes, and GSI attribute projection limited to needed attributes. Enable Provisioned + auto-scaling for predictable traffic with daily peaks; switch to On-Demand when swings are extreme (e.g., 10 to 10,000 reads/sec).
Caching to Cut Database Cost
A cache layer reduces reads hitting the database, lowering required IOPS/RCU and letting you run a smaller instance, while improving latency.
| Cache | Pairs with | Hit latency |
|---|---|---|
| ElastiCache (Redis/Valkey) | any DB | sub-millisecond |
| DynamoDB DAX | DynamoDB only | microseconds |
| CloudFront | API/web responses | edge milliseconds |
| API Gateway caching | API responses | milliseconds |
On the Exam: "Read-heavy, reduce DB cost" → add ElastiCache or read replicas. "Variable/unpredictable DB load" → Aurora Serverless v2 or DynamoDB On-Demand. "DynamoDB microsecond reads" → DAX, not ElastiCache.
Worked Example: Scale Out Instead of Up
A reporting application runs on a single large RDS instance that is CPU-bound only because of heavy read traffic; writes are light. The instinctive fix — upsize the primary — doubles the cost of an instance that is mostly idle on writes. The cost-optimized answer is to scale reads out: add one or two read replicas on smaller instance classes, point analytics and dashboard queries at the replica endpoint, and then downsize the primary because it now handles only writes and OLTP.
With Aurora, the reader endpoint load-balances across up to 15 replicas automatically, so you add read throughput in cheap increments rather than buying one oversized primary. Layering ElastiCache in front for the hottest repeated queries cuts read volume further, which can let you shrink instances again — caching and replicas compound.
Worked Example: Part-Time and Scale-to-Zero Databases
Consider a dev/test database used only ~8 hours on weekdays. Three options compete. A Reserved Instance is wrong — it pays for a full year including the ~75% of hours the database is idle. RDS stop/start on a schedule works but needs automation and still bills storage, and RDS auto-restarts any instance stopped longer than 7 days. Aurora Serverless v2 with a 0-ACU minimum is the cleanest answer: it pauses automatically after the inactivity window, resumes on the first connection, and bills only storage while paused.
This scale-to-zero behavior (introduced late 2024) is the modern exam-correct response for intermittent or unpredictable database workloads where you want zero compute cost during idle periods without writing stop/start scripts. For a flat 24/7 production database, reverse the logic: a provisioned instance on a 3-year Reserved Instance beats Serverless v2, whose per-ACU pricing carries overhead at constant high load.
Database-Cost Trap Table
| Tempting wrong answer | Why it fails |
|---|---|
| Upsize primary to fix read load | Pays for write capacity you don't need; replicas are cheaper |
| Reserved Instance for a part-time dev DB | Bills a full year for an idle-most-of-the-time instance |
| Aurora Serverless v2 for flat 24/7 load | Per-ACU overhead exceeds a Reserved provisioned instance |
| DynamoDB Provisioned fixed at peak | Wastes capacity during lulls; On-Demand or auto-scaling fits |
| ElastiCache for DynamoDB microsecond cache | DAX is the DynamoDB-native microsecond cache |
A development database is used only during business hours (8 AM-6 PM, weekdays) and sits idle nights and weekends. The team wants the lowest cost with minimal operational effort. Which option is BEST?
A DynamoDB table sees extremely volatile traffic, swinging from about 10 reads/second to 10,000 reads/second unpredictably through the day. Which capacity mode fits BEST?
A read-heavy reporting application keeps requesting the same DynamoDB items, driving up read capacity cost. Which change reduces RCU consumption with microsecond-latency cached reads?