---
title: "Document or Relational: Read-Time or Write-Time Cost"
description: "Relational modeling describes the entities and lets queries follow. Document modeling inverts that, and the inversion is the whole trade."
url: https://sqlpress.com/blog/access-pattern-first-modeling/
category: NoSQL
tags: ["schema-design", "architecture", "query-optimization"]
author: "Elias Rowe"
published: 2026-10-11T00:00:00.000Z
measured: false
---

# Document or Relational: Read-Time or Write-Time Cost

## Key takeaways

- A document store wins when the aggregate you store matches the unit you read, so one lookup returns everything a request needs.
- It loses when the same data is read through several different shapes, because each shape needs its own copy or its own index.
- The decision is not relational versus document; it is whether you are paying for joins at read time or for duplication at write time.

Both models pay for the same thing at different times. The relational one keeps a
single copy and assembles shapes on read, paying in join work; the document one
stores assembled shapes and pays in duplication and write coordination.

AWS states the inversion in its own design guidance: "Instead of reshaping data
when a query is processed (as an RDBMS system does), a NoSQL database organizes
data so that its shape in the database corresponds with what will be queried." The
same page is explicit about the order of work — you are told not to design the
schema until you know the questions it has to answer. What follows is where each
side of that trade is cheap.

## When does a document store fit the access pattern?

An order with its line items, shipping address, and status history is one document.
The order page reads it with one request. There is no join because there is nothing
to join — the boundary of the stored object is the boundary of what the page needs.

That is the case where a document store is not a compromise. The read is a single
key lookup returning exactly the required bytes, and it stays a single key lookup
at any data volume, because nothing about it scans.

The same property makes writes clean when they arrive at the same granularity.
Adding a line item rewrites one document.

## When does document modeling stop working?

**A second access pattern with a different shape.** Now you also need "all orders
for a customer" and "all orders containing product X". Neither is a lookup on the
order key. The answers are a secondary index, or a second copy of the data keyed
differently, and in DynamoDB's single-table designs that is the explicit technique.
The relational counterpart is another index on the same table, where
[the column order decides which predicates it can serve](/blog/composite-index-column-order/).

Each copy is a write amplification and a consistency obligation. Two copies of an
order mean two writes, and something has to reconcile them if the second fails.

**Ad-hoc questions.** "Orders over 500 euros from customers in Portugal placed last
March" is a query nobody modeled. Relationally it is a `WHERE` clause — one that
still depends on [the planner deciding an index is worth
using](/blog/index-not-used-estimate-not-index/), but one that needs no schema
change to run. In a document store it is a full scan,
or an analytics copy of the data kept somewhere else.

**Unbounded embedding.** A document that grows with activity — an audit trail, a
comment thread — eventually hits the size limit, which in MongoDB is 16 MiB, and
degrades long before that because every read transfers the whole document. Embed
bounded collections; reference unbounded ones.

## Which bill is smaller

Embedding bounded collections and referencing unbounded ones is one instance of the
trade the opening named: a shape you store cheaply now is a shape you pay to keep
correct later.

| | Relational | Document or key-value |
|---|---|---|
| Copies of a fact | one | one per shape that needs it |
| Cost of a new shape | a query, sometimes an index | a copy or an index, plus write coordination |
| Cost of an unmodeled question | a `WHERE` clause | a full scan, or an analytics copy elsewhere |
| When the cost is paid | read time | write time |

The join work is paid by whatever assembles the shape, and an ORM that assembles it
lazily pays it as [one query per element of the collection](/blog/n-plus-one-queries/).
The duplication is paid by whatever keeps the copies agreeing, on every write rather
than on the reads that benefit from it.

Which is cheaper depends on the read/write ratio and on how many distinct shapes
exist. A small number of well-known access patterns with a high read rate favors
the document model strongly. A large or growing number of shapes favors the
relational one, and the growth is usually not predictable at design time.

## What would change the conclusion

That balance holds only while the number of shapes does, and two things move it.

If a new access pattern appears every quarter, the document model accumulates
copies and the cost of each new shape rises. If the access patterns are fixed by a
narrow API contract, they do not.

And if the workload requires transactions across aggregates, the argument weakens
considerably. MongoDB supports multi-document transactions, but needing them
regularly is a signal that the aggregate boundary was drawn in the
wrong place — which is a modeling problem, not a technology problem.

## FAQ

### When should I use a document store instead of a relational database?

When the aggregate you store matches the unit you read. An order with its line items, shipping address and status history is one document, and the order page reads it with a single key lookup that stays a single key lookup at any data volume. The model loses that advantage as soon as the same data is read through several different shapes, because each shape needs its own index or its own copy.

### What is the maximum MongoDB document size?

MongoDB caps a document at 16 MiB. A document that grows with activity — an audit trail, a comment thread — eventually reaches that limit, and it degrades long before reaching it, because every read transfers the whole document. The rule that follows is to embed bounded collections and reference unbounded ones.

### Why does DynamoDB single-table design duplicate data?

Because a key-value store answers lookups on the key an item is stored under, and nothing else. A second access pattern with a different shape — all orders for a customer, all orders containing a product — is not a lookup on the order key, so the answer is a secondary index or a second copy of the data keyed differently. Each copy is a write amplification and a consistency obligation.

### Can a document store answer ad-hoc queries?

Not without scanning. A question nobody modeled, such as orders over 500 euros from customers in Portugal placed last March, is a WHERE clause in a relational database. In a document store it is a full scan, or an analytics copy of the data kept somewhere else. Access-pattern-first modeling assumes the patterns are known before the data is stored.

## Sources

- [MongoDB Manual — Data Modeling](https://www.mongodb.com/docs/manual/data-modeling/) (docs)
- [Amazon DynamoDB Developer Guide — NoSQL design for DynamoDB](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/bp-general-nosql-design.html) (docs) — Access patterns are identified before the schema; as few tables as possible; global secondary indexes serve queries the main table cannot.
- [MongoDB Manual — BSON Document size limit](https://www.mongodb.com/docs/manual/reference/limits/) (docs) — The 16 MiB document limit that bounds how much can be embedded.
