Why data models matter: my takeaways on SQL and documents
I used to think choosing a database was mainly a performance decision. This reading changed that for me. The data model comes first because it affects how I describe the problem, how the application changes, and which queries feel easy or painful later.
A data model is a useful boundary
An application sits on several layers of representation. I might model a product, user, payment, or relationship as an object in code. That object is then stored as a row in a table, a JSON document, or a graph. The database turns that model into bytes, and the hardware stores those bytes.
Each layer hides complexity from the one above it. That is useful, but it also means each model comes with opinions. Some operations fit naturally. Others need workarounds. The choice should follow the shape of the data and the questions the product needs to answer.
DATA MODEL LAYERS
Real-world concepts
-> application objects and APIs
-> tables | documents | graphs
-> bytes and storage
SQL and documents solve different problems
Relational databases organize information into tables, rows, columns, and references. They fit well when the same fact is shared by many records and relationships matter. A user, organization, order, and payment can live in separate tables and be connected with IDs.
Document databases store related fields together, often as JSON. They feel natural when one record is mostly self-contained. A user profile can hold basic details, contact information, previous roles, and education in one document. Reading the profile may then be one fetch instead of several table reads and joins.
DATA SHAPE
Self-contained tree
-> document model
Shared, linked facts
-> relational model
Neither approach is automatically better. The useful question is whether the data is mainly a tree owned by one parent, or a set of entities connected in many directions.
A profile may start as one neat document. Then the product grows. Organizations get their own pages. Schools need logos and descriptions. Users recommend one another. Those additions create shared entities and many-to-many relationships.
Duplicating an organization name, school details, or profile image inside many documents makes updates harder and increases the chance of inconsistent data. In a relational model, the shared fact can live once, have an ID, and be referenced by other records. The database can join the pieces when a query needs them.
Why relational databases won
Early hierarchical databases also stored data as nested trees. They worked well for one-to-many relationships, but developers had to duplicate shared data or manually follow references when relationships became more complex.
The network model allowed a record to have multiple parents, but queries depended on pointer-like access paths. Developers had to know exactly how to navigate the database. A new query path could mean rewriting the data model and the application code that followed it.
Relational databases changed that division of work. An application describes the result it wants, while the database query optimizer chooses indexes, join methods, and execution order. Adding an index later can improve a query without changing the application query itself.
RELATIONAL QUERYING
Application
-> describes needed result
Query optimizer
-> chooses indexes, joins, and order
Normalization is about avoiding conflicting copies
Normalization is less about memorizing formal rules and more about storing a shared fact in one place. A canonical record for a region or industry supports consistent spelling, avoids ambiguity, makes localization easier, and gives search a reliable value to match. An ID can remain stable even when the human-facing name changes.
Reading related data may require joins. A document store can shift that work into application code if joins are weak, but repeated application-side lookups often make the code more complex and less efficient as relationships multiply.
NORMALIZATION
Duplicate facts
-> many updates
-> inconsistency risk
Canonical record + IDs
-> one update
Schema flexibility has a trade-off
Document databases are often called schemaless, but application code still expects particular fields and shapes. The schema exists, even when the database does not enforce it.
Schema-on-read means the application interprets a document's structure when it reads it. This works well when records are genuinely different or an external system controls the format. Schema-on-write validates data before it is stored. It is useful when records should follow the same structure because it documents and enforces that expectation.
Changing a format can be handled in either model. A document application can write new fields and support old documents while reading them. A relational database can add columns and migrate rows. The expensive part is often rewriting a large amount of existing data, not the fact that one model has a schema.
SCHEMA CHOICE
Schema-on-read
-> interpret structure when reading
Schema-on-write
-> validate structure before storing
Document locality helps only when it matches the read
A document is usually stored together. If an application needs most of that document at once, one read can be efficient. But a database often loads the entire document even when a query needs only one small field, and updates may rewrite the full document.
That is why documents should generally stay reasonably small and should not be used blindly for records that grow continuously. Related rows can also be grouped together in relational systems, so locality is a storage-design idea rather than a document-only advantage.
NoSQL did not replace SQL
NoSQL grew because some applications needed high write throughput, large-scale distribution, specialized queries, looser schemas, or open-source alternatives. It was not proof that relational databases were outdated.
The more useful idea is polyglot persistence. A system can use the storage model that suits each job. A relational database can handle core records and relationships, a document store can keep flexible aggregates, and a search index can serve discovery. Relational and document databases are also converging: relational systems increasingly support JSON, while document systems add more ways to handle references and joins.
POLYGLOT PERSISTENCE
One system
-> relational DB for core relationships
-> document store for flexible aggregates
-> search index for discovery
How I will choose a data model
I will start with the data and access patterns instead of asking which database is popular.
- Is this record mostly owned by one parent and read as a whole? A document may fit well.
- Are facts shared across many records? References and normalization are likely safer.
- Will the product gain more relationships over time? I should expect joins or consider a graph model.
- Which queries must be simple and fast? The model should make those queries natural.
- What will need to change later? A convenient shortcut today can make the next feature expensive.
The database model is part of the product design. It influences the code, the queries, and the changes that will be easy to make later.
These are my personal learning notes from Designing Data-Intensive Applications by Martin Kleppmann.