· Part 3/6 · Choosing AWS services under constraint
Pick the database for the query you cannot avoid
Eleven services, six comparison tables, and one of them is already end-of-life. Database selection is decided by the query you cannot avoid and by whether two users may see different rows.
AWS’s database guide covers eleven services across six tables: data model and use cases, scalability, consistency and engine compatibility; then pricing, backup, recovery, monitoring and migration; transaction support; the availability target; the management model and operational overhead; and finally a set of decision scenarios.
Those are the right axes, and the document is careful. They are also axes on which most of the eleven look defensible for most workloads, which is why reading it end to end narrows the field so little.
Part of that is what the guide is for. Its last section is headed “Exam-Focused Decision Guide”, and that is an honest label: it is built for certification recall, where the job is to remember which service owns which capability. Selecting for a system you have to run is a different job, and it starts from constraints rather than from capabilities.
Two questions narrow it immediately.
Which query can you not avoid?
Every data model is a bet about which questions will be cheap. A key-value store bets that you will look things up by key, and pays for that bet with everything else. A relational engine bets that you do not know the questions yet, and pays for it in write throughput and in the operational care a single primary demands.
So the useful question is not “what shape is our data”. It is: what is the one query we will definitely have to answer, that we cannot design our way out of?
Usually there are only two or three candidates, and usually one of them is awkward — a report finance needs, a reconciliation, an “show me everything touching this customer” that crosses four entities. That awkward one decides the engine, because everything else can be denormalised, cached or precomputed around it. The pretty queries are not the constraint. The ugly one is.
The wrong turn here is picking for the pretty queries. A team designs around their access patterns, ships, and then discovers the compliance report needs a cross-entity scan the table shape makes impossible — and now they are running a second store, a pipeline between the two, and a permanent consistency question nobody wanted.
May two users get different answers to the same query?
This is the question that most often turns out to be the real constraint, and it is in nobody’s comparison table.
If the CFO and a new intern run the same query and must get different rows back, you have made a decision about where authorisation lives. There are only three honest places for it:
- In the query. Every caller adds the right predicate. This works until somebody forgets, and the failure is silent — a report with too many rows in it looks exactly like a report.
- In the engine. Row-level policies enforced below the application. Fewer engines support this than people assume, and the ones that do make it a schema-design decision rather than an afterthought.
- In a service in front of the data. Everything goes through one path that knows who is asking. Correct, and it means that path is now the thing that must never be bypassed — including by the analytics pipeline, which is exactly how it gets bypassed.
Pick one deliberately. The failure we see is picking none of them explicitly, which in practice means the first one, unwritten.
This matters twice over for retrieval systems. A permission-aware RAG pipeline inherits whatever the store enforces — and if the answer is “nothing, we filter in the application”, then the embedding index built from that store is a copy of the data with the filtering left out. A summary that crossed the line is still a leak, and it is a leak nobody can see in the logs.
Run the sieve
Which of these are true for you?
Still standing11 of 11
Amazon RDS
A managed instance of an engine that exists outside this cloud — PostgreSQL, MySQL, MariaDB, SQL Server, Oracle, Db2 — with the query planner people already know.
Amazon Aurora
Wire-compatible with PostgreSQL and MySQL, with storage that grows on its own, failover in seconds, and a global option for reading close to the customer.
Amazon DynamoDB
Predictable single-digit-millisecond access at any size, with global tables that take writes in several regions — provided you know the access pattern before you design the table.
Amazon DocumentDB
Document storage for applications already written against that data model, speaking a MongoDB-compatible API.
Amazon ElastiCache
A cache — Redis OSS, Valkey or Memcached — fast because it is allowed to forget.
Amazon MemoryDB
In-memory speed with a durable transaction log behind it — the answer when something needs microsecond reads and is also the system of record.
Amazon Neptune
Graph storage for questions about relationships several hops out — Gremlin, openCypher and SPARQL over the same data.
Amazon Keyspaces
Cassandra CQL without running Cassandra — wide-column storage at large scale, with tunable consistency and multi-region replication.
Amazon Timestream
Purpose-built time series — telemetry, metrics, sensor data — with ingest and retention tiering handled for you.
Amazon QLDB
An immutable, cryptographically verifiable ledger — an append-only journal you could prove had not been altered.
Amazon Redshift
Columnar warehousing for questions over the whole history rather than one row of it — the place the ad-hoc queries actually belong.
Our reading, not a specification. Service behaviour changes — check any elimination that decides something against the service page before you design around it.
All eleven services the guide covers are in there, including the one being retired — see below.
Two of them never narrow to a recommendation however you set the questions, and that is a finding rather than a gap in the widget.
The ledger database is never recommended because it is being withdrawn. It can be eliminated and it can never be chosen, which is the correct behaviour for a service with an end-of-life date.
The document database is never the last one standing either, and the reason is more interesting: it is not selected by constraints. Nothing about a greenfield problem points at it that a relational engine or a key-value store does not answer at least as well. What points at it is an application that is already written against a document API and whose queries nobody is going to rewrite. That is a fact about your estate, not a property of the workload — and it is worth knowing which of your options are in that category, because a migration target and a design choice are different kinds of decision made by different people for different reasons. The same is largely true of the wide-column option.
Try the questions are about connections, several hops out on its own: exactly one service survives, which is the clearest example in the series of a single constraint settling a decision outright. Then try the questions are not known in advance together with traffic can multiply without warning. That pair is the genuine tension in this category, and almost every architecture that ends up with two datastores got there by refusing to choose between them. Which is sometimes correct — but it should be a decision with a written reason, not a drift.
Four decisions the eleven actually turn on
The guide ends with a list of scenarios, which is the most useful thing in it. Here are four, with the discriminator named rather than the services listed.
Microsecond reads. Two services answer this, and the question that separates them is not speed — it is what happens when the process restarts. A cache is fast partly because it is permitted to lose things; an in-memory database with a durable transaction log is not. If losing the contents means recomputing from somewhere else, the cache is correct and cheaper. If losing the contents means losing the record, you were never shopping for a cache.
Cross-region. Almost everything on the list has something labelled global, and they are not the same thing. Read replicas in another region are disaster recovery: an RPO, an RTO, and a promotion step somebody has to perform. Tables that accept writes in several regions are a different architecture with a different failure mode — concurrent writes to the same item now resolve by a rule, and that rule is your data model’s problem. Decide which of the two you are buying before comparing anything, because the shortlists barely overlap.
Relational at unpredictable scale. The relational options scale reads readily and writes reluctantly, because a single writer is what makes the transactional guarantee cheap. If write volume genuinely multiplies without warning, either the access pattern is known well enough for a key-value store, or the spike has to be absorbed in front of the database rather than by it. “Make the instance bigger” is a plan with a maintenance window in it.
Verifiable immutability. This one has changed since the guide was written — see below.
The service that is already gone
One of the eleven is marked EOL in the guide itself: the ledger database, whose whole proposition was an append-only journal you could cryptographically prove had not been altered. That is a real requirement — systems of record, audit trails, supply-chain provenance — and the managed service that answered it is being withdrawn.
Two things worth taking from that.
The first is practical. Verifiable immutability now means building it: an append-only table in a relational engine, a hash chain over the rows, and a periodic anchor somewhere you do not control. More work, and nobody can retire it.
The second is about decision guides generally. This one is accurate and it already contains a service you must not build on — and it says so, which is more than most such documents manage. A comparison table is a photograph. Before you design around any narrow, purpose-built managed service, open its own page and check what it says today. That advice applies to this article too.
Then, and only then, the specifications
Narrowing by constraint gets you to two or three. Choosing between two or three is a different job, and it does need the comparison table — the data model, the consistency guarantee, how the thing scales, what survives a region going away, and the shape of the bill.
So here is that table, filterable. It comes second on purpose.
Compare what is left
This filters on what each service is, which only helps once you know roughly what you are looking for. Narrow by constraint first.
Everything, so far11 of 11
Amazon RDS
- Engines
- PostgreSQL, MySQL, MariaDB, SQL Server, Oracle, Db2
- Billing
- Instance hours, storage, IOPS, data transfer
- Recovery
- Snapshot restore and point-in-time restore, into a new instance
Amazon Aurora
- Engines
- MySQL and PostgreSQL compatible
- Billing
- Instance hours or capacity units, storage, I/O, backup storage
- Recovery
- Snapshot, point-in-time restore, and in-place rewind
Amazon DynamoDB
- Engines
- Proprietary API — no counterpart to migrate to
- Billing
- Request units or provisioned capacity, storage, backup storage
- Recovery
- Continuous point-in-time restore into a new table
Amazon DocumentDB
- Engines
- MongoDB-compatible API
- Billing
- Instance hours, storage, I/O, backup storage, data transfer
- Recovery
- Snapshot and point-in-time restore, into a new cluster
Amazon ElastiCache
- Engines
- Redis OSS, Valkey, Memcached
- Billing
- Node hours, or serverless capacity and GB-hours
- Recovery
- Snapshot restore into a new cluster — it is a cache
Amazon MemoryDB
- Engines
- Redis OSS, Valkey
- Billing
- Node hours
- Recovery
- Durable transaction log, snapshots, multi-region
Amazon Neptune
- Engines
- Gremlin, openCypher, SPARQL
- Billing
- Instance hours or serverless capacity, storage, I/O
- Recovery
- Snapshot and point-in-time restore
Amazon Keyspaces
- Engines
- Apache Cassandra CQL
- Billing
- On-demand requests or provisioned capacity, storage
- Recovery
- Point-in-time restore, multi-region replication
Amazon Timestream
- Engines
- SQL-like, and an InfluxDB-compatible option
- Billing
- Ingest, storage tier and query — serverless throughout
- Recovery
- Retention tiers and AWS Backup integration
Amazon QLDB
- Status
- End of life — the guide itself says so. Do not build on it.
- Engines
- PartiQL over a proprietary journal
- Billing
- Serverless: I/O, storage and journal
Amazon Redshift
- Engines
- PostgreSQL-derived SQL
- Billing
- Node hours or serverless capacity, plus managed storage
- Recovery
- Snapshots, point-in-time restore, cross-region snapshot copy
Several ticks in one group widen the result; ticks in different groups narrow it. Monitoring and Multi-AZ are not filters here: every one of the eleven has both, so neither can change the result.
Two things worth noticing about it.
It only helps if you already know what you want. To filter by data model you have to have decided on a data model, which is most of the decision. That is the difference between this and the sieve above, and it is the reason the vendor’s guide — which is entirely of this kind — narrows so little on its own. A feature matrix is a reference, not a decision procedure.
Two of the guide’s columns are missing here, and finding them was the useful part of building it. Monitoring: for all eleven the answer is CloudWatch and CloudTrail with a service-specific extra or two. Multi-AZ: all eleven have it. Neither can ever change the result, so neither gets a checkbox — a control that cannot affect the outcome still implies a decision is being made, which is worse than leaving it out. Backup and recovery are folded into one group for a milder version of the same reason: nearly everything has snapshots and point-in-time restore, and only the genuinely different capabilities — in-place rewind, writes accepted in more than one region — are worth asking about.
Which is the useful thing to take from any comparison table: the columns where every row says roughly the same thing are the columns that were never going to decide anything. Read them once to know they are covered, then go back to the constraints.
The exit question
One constraint in the sieve above is worth arguing about: we must be able to leave.
It is easy to treat this as paranoia, and easy to treat wire compatibility as satisfying it. Neither is right. Wire compatibility means your driver connects. It does not mean the behaviour you tuned against — the failover timing, the replication lag, the way the planner handles your worst query — comes with you. Those are the things an application quietly grows to depend on, and they are precisely what differs.
The practical version is not “avoid managed engines”. It is: know which behaviours you depend on, write them down, and check them against the destination before you claim the exit exists. A migration path nobody has tested is not a migration path; it is a sentence in a risk register.
Next: application integration, where the equivalent buried question is what happens on the bad day.