Recommend a Data Storage Solution to Balance Features, Performance, and Costs — Lesson
AZ-305 › Unit 2 › Design data storage for semi-structured and unstructured data › Recommend a data storage solution to balance features, performance, and costs
Recommend a Data Storage Solution to Balance Features, Performance, and Costs — Lesson
Choosing the right Azure data store is rarely about which service is "best" — it is about which trade-offs you can accept. Every storage decision lands somewhere on a triangle of features, performance, and cost, and every service in Azure's data portfolio occupies a different corner. This lesson teaches you to map a workload's characteristics to the storage service whose trade-offs most closely fit, then defend the choice against close-but-wrong siblings on the AZ-305 exam.
This is a synthesis lesson. You have already met the individual services in LO12–LO17; here you will learn the decision framework that lets you pick between them under pressure — and the cost levers that most architects miss until the bill arrives.
Why This Matters
Cloud data services lure architects with limitless scale, but every dimension of "limitless" carries a price tag. A single bad choice — picking Azure SQL Database Hyperscale for a key-value cache, or Cosmos DB for a reporting workload — can multiply a workload's monthly bill by ten with no functional benefit. The AZ-305 exam tests this trade-off literacy directly: every data-storage scenario has a plausible-looking distractor, and the difference between "right" and "wrong" is usually a cost or feature constraint hidden in the requirements paragraph. Mastering this skill is what separates a Senior Cloud Architect from a vendor-trained generalist.
Prerequisites
- LO12–LO17 (data services overview) — Can you name three workloads each for
Cosmos DB,Azure SQL Database, andBlob Storage? - Consistency models — Can you explain bounded staleness in two sentences?
- Throughput units — Do you know what a
Request Unit (RU)represents inCosmos DB? - Pricing dimensions — Can you list the three things you pay for in any Azure data service (storage, throughput, egress)?
- Well-Architected Framework — Cost Optimization pillar — What is the difference between right-sizing and reserved capacity?
Learning Objectives
By the end of this lesson, you will be able to:
- Analyse a workload's data shape, access pattern, and SLA against Azure's data-service catalogue.
- Evaluate competing services along the features × performance × cost triangle.
- Recommend a primary store and, if appropriate, a polyglot persistence pairing.
- Calculate the order-of-magnitude monthly cost difference between two candidates.
- Defend the choice against the four most common AZ-305 distractor patterns.
Building Blocks
Polyglot persistence — Like staffing a kitchen with a sushi chef, a pastry chef, and a grill cook instead of one generalist. Formally, the practice of using multiple specialised data stores in a single application, each handling the data shape it serves best. Why it matters: the AZ-305 exam frequently tests whether you can split a workload across two services rather than forcing it into one.
Request Unit (RU) — A pre-paid token that represents the CPU, memory, and IOPS to perform one 1 KB point read against Cosmos DB. Formally, a normalised currency for throughput in Cosmos DB, decoupling the consumer's mental model from the underlying physical resources. Why it matters: every Cosmos DB cost question reduces to RU/s × hours × regions.
DTU and vCore — Two pricing models for Azure SQL Database. DTU bundles compute, memory, and I/O into one blended unit; vCore unbundles them and lets you pay for memory and IOPS separately. Why it matters: the exam often hides the right answer behind a clue like "predictable storage growth" (vCore wins) or "small unpredictable workload" (DTU wins).
Hot, Cool, and Archive tiers — Like the difference between your fridge, freezer, and deep-storage chest. Formally, three storage classes for Azure Blob Storage differing in storage cost, access cost, and minimum retention. Why it matters: a single tier decision can change a 100 TB workload's monthly bill by a factor of 20.
RPO and RTO — Recovery Point Objective is how much data you would lose; Recovery Time Objective is how long it takes you to start serving again. Formally, two independent SLAs that together define a workload's business continuity posture. Why it matters: data-store choice is often dictated by RPO/RTO before performance even enters the conversation.
Egress charge — The fee Azure levies when bytes leave a region or leave Azure entirely. Formally, network outbound transfer cost. Why it matters: a "cheap" store paired with a chatty cross-region client is rarely cheap once egress accumulates.
Deep Dive
Mapping data shape to service category
The first cut in any data-storage decision is the shape of the data, not the volume or the SLA. Get this wrong and you are paying a premium for the wrong primitives. Azure's data portfolio splits into six shape buckets.
| Shape | Primary candidate | Wrong-but-plausible alternative |
|---|---|---|
| Relational, transactional | Azure SQL Database | Cosmos DB SQL API |
| Document (JSON) | Cosmos DB SQL API | Azure SQL with JSON columns |
| Key-value, ultra-low-latency | Azure Managed Redis | Cosmos DB Table API |
| Wide-column, time-series | Cosmos DB Cassandra API | Azure Data Explorer |
| Graph | Cosmos DB Gremlin API | Azure SQL with self-joins |
| Unstructured (blobs, media) | Azure Blob Storage | Azure Files |
[!TIP] When the question gives you a JSON sample with deeply nested arrays and asks for "single-digit-ms reads at scale," the answer is almost always
Cosmos DB SQL API. If the same data is described as "tabular with strict referential integrity," it isAzure SQL Database.
The features × performance × cost triangle
Every data-store decision sits inside a triangle. You can pick any two corners; the third bends to fit. The trick on the AZ-305 exam is to identify which two corners the question is anchoring, then pick the service whose third corner is acceptable.
[!IMPORTANT] The exam will sometimes describe a workload that appears to need
Cosmos DB(multi-region, JSON) but the binding constraint is "minimise cost for under 100 GB and under 100 RPS." That isAzure SQL Database Serverlesswith aJSONcolumn — the single-region trade-off is acceptable.
Performance dimensions: RU/s, DTU, IOPS, and TPS
These four units measure different things, and conflating them is the most common source of incorrect sizing on the exam.
| Unit | Service | What it measures | Sizing heuristic |
|---|---|---|---|
| RU/s | Cosmos DB | Normalised throughput per second | 1 KB point read = 1 RU; 1 KB write = 5 RU |
| DTU | Azure SQL (DTU model) | Bundled compute + memory + I/O | Doubling DTU doubles throughput |
| IOPS | Azure SQL Hyperscale, Premium SSD | Disk I/O operations per second | Each P30 data disk = IOPS |
| TPS | Generic application metric | Transactions per second | 1 TPS may be 1 RU or 50 RU depending on size |
// Estimate RU consumption for a Cosmos DB container over a week
AzureDiagnostics
| where ResourceType == "DATABASEACCOUNTS"
| where Category == "DataPlaneRequests"
| summarize TotalRUs = sum(toreal(requestCharge_s)) by bin(TimeGenerated, 1h)
| order by TimeGenerated asc[!WARNING] A single 1 MB write against a
Cosmos DBcontainer can cost more than 200 RU. If your workload bursts large documents, provisioned RU/s sized for the average will throttle (HTTP 429) on every burst. UseAutoscaleorServerlessinstead.
Cost models — what you actually pay for
Every Azure data service charges across four dimensions. Mastering the pricing structure is what makes a recommendation defensible.
| Service | Storage | Throughput | Operations | Egress |
|---|---|---|---|---|
Cosmos DB | per GB-month | per RU/s-hour (or per request — Serverless) | included in RU | per GB |
Azure SQL DB | included in DTU; separate in vCore | bundled (DTU) or unbundled (vCore) | included | per GB |
Blob Storage | per GB-month per tier | none (pay-per-op) | per ops | per GB |
Azure Files | per GB-month per tier | provisioned IOPS (Premium) | included | per GB |
Synapse Dedicated SQL | per TB-month | per DWU-hour | included | per GB |
resource cosmos 'Microsoft.DocumentDB/databaseAccounts@2024-05-15' = {
name: 'cosmos-prod-001'
location: location
kind: 'GlobalDocumentDB'
properties: {
databaseAccountOfferType: 'Standard'
consistencyPolicy: { defaultConsistencyLevel: 'Session' }
locations: [
{ locationName: 'eastus', failoverPriority: 0 }
{ locationName: 'westeurope', failoverPriority: 1 }
]
capabilities: [
{ name: 'EnableServerless' } // pay per request, no min RU/s
]
}
}# Inspect provisioned vs autoscale RU configuration on a container
az cosmosdb sql container throughput show \
--account-name cosmos-prod-001 \
--resource-group rg-data \
--database-name shop \
--name products \
--query "resource.{ru:throughput, autoscaleMax:autoscaleSettings.maxThroughput}"[!NOTE]
Cosmos DB Serverlesscaps each container at RU/s and 1 TB. It is the right answer when traffic is bursty, sub- RU/s, and total data fits comfortably under the cap.
Pairing services — polyglot persistence
The exam frequently tests whether you can recommend two services working together instead of forcing one. The canonical "hot path / cold path" architecture below has Redis absorbing read-heavy traffic, Cosmos DB as the system of record, and Synapse running the analytical queries that would crush an OLTP store. Each piece earns its keep.
Reserved capacity and committed-use discounts
Lift-and-shift cost optimisation often starts with right-sizing, but the second lever — reserved capacity — is what closes the gap with on-prem economics. Cosmos DB offers 1- and 3-year reservations on RU/s with savings of 20% to 65%. Azure SQL Database and Synapse Dedicated SQL Pool both support similar reserved capacity. The catch is that reservations apply to a region and SKU family — moving from vCore General Purpose to Business Critical mid-term forfeits the discount. Recommend reservations only after a workload has been stable for at least one quarter.
| Lever | Typical saving | Workload fit |
|---|---|---|
| Right-sizing (Autoscale) | 30%–50% | Bursty, predictable peaks |
| Serverless | 40%–70% | Sub- RU/s, intermittent |
| Reserved capacity (1 yr) | 20%–40% | Steady-state production |
| Reserved capacity (3 yr) | 40%–65% | Long-lived, post-migration |
[!TIP] Stack levers in order: right-size first (free), then choose Serverless or Provisioned, then layer a reservation on the survivor. Reserving an oversized SKU just locks in the overpayment.
Worked Examples
Easy — Document store for a product catalogue
Problem: Contoso runs an e-commerce site with SKUs. Each product is a JSON document with deeply nested specifications. The team wants under 20 ms read latency globally and expects 200 RPS at peak. Single-region writes are acceptable.
Solution:
- Data shape is JSON, deeply nested →
Cosmos DB SQL APIis the leading candidate. - Under 20 ms global reads → multi-region read replicas via
Cosmos DB's automatic geo-replication. - Single-region writes → do not pay for multi-master.
- 200 RPS at KB per read RU/s — well under the RU/s
Serverlesscap.
Recommendation: Cosmos DB SQL API, Serverless tier, single write region, two read replicas. Estimated monthly cost: .
[!NOTE] The trap here is
Azure SQL Databasewith aJSONcolumn. It works, but global ms reads require expensiveGeo-Replicationand active replicas — a multi-x cost increase.
Medium — Choosing between Hyperscale and Cosmos DB
Problem: Fabrikam has a 20 TB transactional workload growing 1 TB/month. The schema is highly relational with 400+ stored procedures, but the team is pushing to "modernise to NoSQL" because they hit storage limits on Azure SQL Database General Purpose (4 TB cap).
Solution:
- The pull is "we hit a cap" — but the cap is the GP tier limit.
Hyperscaleraises this to 100 TB. - 400+ stored procedures means lift-and-shift to
Cosmos DBis a 6-month rewrite. - ACID across multiple tables is native to
Azure SQL, awkward inCosmos DB(transactional batch is single partition only).
Recommendation: Migrate to Azure SQL Database Hyperscale. Cost is comparable for this volume; rewrite avoidance is decisive.
[!NOTE] The "modernise to NoSQL" framing is a classic distractor. The right question is "what is the migration cost?" not "what is trendy?".
Hard — Hot path plus cold path for an IoT workload
Problem: Northwind Energy ingests telemetry messages/sec from wind turbines. Operations needs sub-second alerting on anomalies; data scientists need historical analytics over 2 years of data ( TB). Budget pressure: this workload must come in under /month.
Solution: One service cannot satisfy both halves. Split the architecture.
| Path | Service | Why |
|---|---|---|
| Ingestion | Event Hubs Standard, 20 TUs | Buffers msg/sec |
| Hot path | Azure Stream Analytics to Cosmos DB (last 30 days) | Sub-second windowed alerts |
| Cold path | Azure Data Lake Storage Gen2 (Cool tier) | 600 TB at /GB-month |
| Analytics | Synapse Serverless SQL Pool over the lake | Pay-per-query, no warm cluster |
Recommendation: Polyglot — Cosmos DB (small TTL window) + ADLS Gen2 Cool + Synapse Serverless. Total estimated cost /month.
[!NOTE] Putting the full 600 TB in
Cosmos DBwould exceed /month at the cheapest RU/s tier. The "wrong answer" looks elegant on a whiteboard but is unaffordable in production.
Visual Explanations
Decision tree for the primary data store
Caption: The first cut is data shape; the second is access pattern. Each leaf is a service plus tier combination ready to be sized.
Cost-per-TB across services (illustrative spatial view)
Caption: Order-of-magnitude USD cost per TB-month. Note the × spread between Cosmos DB and Blob Archive — picking the wrong tier is rarely a 10% decision.
Feature parity matrix
| Feature | Cosmos DB SQL | Azure SQL DB | Blob | Synapse | Redis |
|---|---|---|---|---|---|
| ACID transactions | Single partition only | Yes | No | No (DW pattern) | Single key |
| Multi-region writes | Yes | No (read replicas only) | Yes (RA-GZRS) | No | Premium tier |
| SLA — read | 99.999% | 99.99% | 99.99% (RA-GRS) | 99.9% | 99.9% |
| Schema flexibility | Schema-less | Strict | N/A | Strict | Schema-less |
| Native time-to-live (TTL) | Yes | No | Lifecycle policy | No | Yes |
| Geo-failover RTO | Seconds | Minutes (auto-failover groups) | Hours (manual) | Minutes | Seconds |
Caption: A side-by-side parity check. Note that Cosmos DB's 99.999% read SLA is the only five-nines in the portfolio.
Common Mistakes
❌ Myth: "
Cosmos DBis always the right NoSQL choice in Azure." ✅ Reality:Cosmos DBexcels at globally distributed, single-digit-ms scenarios. For a single-region key-value cache,Redisis 5–10× cheaper. For analytics over historical data,SynapseoverADLS Gen2wins on cost by an order of magnitude. Why it's tricky:Cosmos DB's marketing and exam vocabulary make it the "default NoSQL," but the AZ-305 exam tests whether you can identify when a cheaper sibling fits.
❌ Myth: "Provisioned RU/s is always more economical at scale than Serverless." ✅ Reality: Provisioned wins above RU/s of steady utilisation. For bursty workloads averaging 200 RU/s with RU/s peaks, Serverless is cheaper and avoids
HTTP 429throttling. Why it's tricky: Architects size Provisioned for the peak (overpay 80% of the time) or for the average (throttle on peaks). Serverless removes that dilemma below RU/s.
❌ Myth: "Blob Archive tier is the cheapest for everything you do not access often." ✅ Reality: Archive has a 180-day minimum retention and a multi-hour rehydration time. If "occasional" means quarterly access, Cool is right; if it means annual, Archive is right. Why it's tricky: The pricing-page sticker for Archive is /TB-month, but the early-deletion fee on a blob deleted at day 90 effectively doubles the cost.
❌ Myth: "ACID transactions across tables are unique to relational databases." ✅ Reality:
Cosmos DBsupports ACID transactions, but only across documents in the same logical partition. Cross-partition or cross-container transactions do not exist; you must redesign the data model or use a saga pattern. Why it's tricky: Candidates rule outCosmos DBover a non-issue (single-partition ACID is plenty for most aggregates) or pickCosmos DBand discover the limitation in production.
Practice Exercises
🟢 Easy 1 — Identify the binding constraint
A retailer needs to store 5 TB of product images. Access is read-heavy from the public website, 99% of reads target images uploaded in the last 30 days. Older images are rarely viewed. Recommend a service and tier.
▶💡 Hint
Two-tier lifecycle. What is the right object store, and what policy moves stale data automatically?
▶✅ Solution
Azure Blob Storage with a Lifecycle Management policy: Hot tier for the first 30 days, then auto-tier to Cool. Add a CDN (Azure Front Door Standard) in front for the public read traffic — the CDN absorbs the bulk of GETs at near-zero marginal cost.
🟢 Easy 2 — Reject a wrong sibling
A team proposes Azure Files Premium to store the chat history of a customer-support bot ( JSON conversations/day, 1 KB each, 90-day retention). Why is this wrong, and what is right?
▶💡 Hint
What does Azure Files charge for, and how does that compare to a JSON-native store?
▶✅ Solution
Azure Files Premium is provisioned by IOPS and around /GB-month — wildly overpriced for 1 KB JSON blobs accessed via app code, not SMB. Recommend Cosmos DB SQL API Serverless or Blob Storage Hot tier with a Cosmos DB Change Feed-style index. The chat history is records, not files.
🟡 Medium 1 — Sizing Cosmos DB throughput
You estimate 400 RPS of 2 KB reads and 50 RPS of 5 KB writes against a Cosmos DB SQL API container, evenly distributed. Is Serverless viable?
▶💡 Hint
Compute peak RU/s. Reads RU each, writes RU each.
▶✅ Solution
Reads: $400 \times 2 = 800$$ RU/s. Writes: $50 \times 25 = 1{,}250 RU/s. Total RU/s — under the RU/s Serverless cap. Yes, Serverless is viable and likely cheaper than provisioning RU/s.
🟡 Medium 2 — DTU vs vCore
A SaaS vendor runs 30 small Azure SQL databases for tenants, each under 5 GB and under 50 DTU. What pricing model and topology should they choose?
▶💡 Hint
"Small + many" hints at elastic pools. Consider per-database vs pool pricing.
▶✅ Solution
Use an Azure SQL Database Elastic Pool with 200 eDTU. The pool absorbs the noisy-neighbour effect across 30 tenants for far less than $$30 \times 50$$ DTU per-database. DTU model wins here because tenant workloads are small and predictable in aggregate.
🟡 Medium 3 — RPO/RTO drives the choice
A regulated financial workload requires RPO seconds and RTO minute, with active reads from a secondary region. Which service?
▶💡 Hint
RPO of 5 seconds rules out async-replicated stores. Active reads from a secondary mean the store must natively expose the secondary.
▶✅ Solution
Cosmos DB with multi-region writes and Strong consistency on the regional pair, or Bounded Staleness if cross-pair. Azure SQL Auto-Failover Groups give RPO s typical but the failover RTO is closer to 30–60 s and the secondary is read-only by default — viable but tighter on the SLA.
🔴 Hard 1 — Polyglot architecture
Design the data tier for a global ride-hailing app. Requirements: ride matching (under 50 ms anywhere), driver location ingest (1 M updates/sec), historical analytics, financial transactions (ACID), and PII data subject to data-residency law in EU and India.
▶💡 Hint
Five workloads, four shapes. Do not try to use one service.
▶✅ Solution
| Workload | Service | Why |
|---|---|---|
| Ride matching | Cosmos DB SQL API multi-region | Under 50 ms global, multi-master writes |
| Driver location | Azure Managed Redis Premium with geo-replication | 1 M ops/sec sustained |
| Historical analytics | ADLS Gen2 plus Synapse Serverless | Cheap PB-scale plus ad-hoc query |
| Payments | Azure SQL Database Business Critical | ACID plus audit plus Always Encrypted |
| EU/IN PII | Region-pinned Cosmos DB accounts (no cross-region replication for those partitions) | Residency compliance |
🔴 Hard 2 — Cost optimisation under constraint
A workload currently runs on Cosmos DB Provisioned at \sim/month. Telemetry shows the average usage is RU/s for 90 minutes/day. Recommend an optimisation.
▶💡 Hint
Three options: Autoscale, Serverless, smaller Provisioned plus queueing.
▶✅ Solution
Autoscale between and RU/s. Autoscale charges $1.5× the provisioned rate per max RU/s but bills only for max-utilised RU/s in any given hour, so off-peak hours bill at \sim 1{,}500 \times 1.5 = 2{,}250$`RU/s. Estimated savings:`$11{,}700$ to \sim/month. Serverless is not viable here — peaks exceed the RU/s cap.
🔴 Hard 3 — Defensible recommendation
A customer is locked into Oracle Database 19c on-prem for a 50 TB application with 400 stored procedures. They want to move to Azure with minimum rewrite. Compare three options and recommend.
▶💡 Hint
The constraint is "minimum rewrite," not "lowest cost."
▶✅ Solution
Three options:
Azure Database for Oracle(via Oracle Cloud@Customer or partner) — minimum rewrite, vendor lock-in continues, premium price.Azure SQL Database Hyperscale— schema and stored procedure rewrite (–12 months), best Azure-native cost, gainsHyperscalestorage.Azure SQL Managed Instance— middle ground; SSMA tooling automates much of the conversion, supports SQL Agent jobs and CLR, no public IP exposure.
Recommendation: Azure SQL Managed Instance Business Critical. Best balance of rewrite cost, runtime cost, and feature parity for a heavy stored-procedure workload.
Summary & Concept Map
- The first decision is data shape; performance and cost come second.
- The features × performance × cost triangle has no service that wins on all three corners.
- RU/s, DTU, IOPS, and TPS are not interchangeable — confusing them is the most common sizing error.
- Cost models split into four dimensions (storage, throughput, operations, egress); the binding cost is workload-dependent.
- Polyglot persistence is often the right answer; resist forcing one service to do everything.
- The AZ-305 exam tests whether you reject the close-but-wrong sibling, not whether you know one service deeply.
- Always price the second-best option — the gap is often smaller than expected, and the second-best may be defensible on rewrite cost or feature simplicity.