NotesDraft/Book Notes

Designing Data-Intensive Applications·Chapter 2 of 3

Data Models and Query Languages

May 16, 2026·1 min read

systemsdatabases

The chapter is framed as relational against document against graph, but the argument underneath is narrower and better: which joins are you willing to pay for, and where do you want to pay for them.

The actual axis

  • Document. Locality is free, joins are expensive or manual. Good when your access pattern really is a tree and you load it whole.
  • Relational. Joins are cheap and declarative, locality is something you engineer. Good when the same data is read many different ways.
  • Graph. Joins are the primary operation and can be variable depth. Good when the relationships are the data.

The claim I found most useful

Document databases did not remove joins. They moved them into application code, where they are less visible, unoptimised, and repeated at every call site. That reframing makes the schema-on-read argument much less appealing than it sounds.

Schema-on-read is not the absence of a schema. It is a schema that lives in whichever code last touched the data.

What dates poorly

The MapReduce section. It is a fine explanation, but the world moved to declarative pipelines and the chapter's framing of it as a middle ground between imperative and declarative is now mostly of historical interest.

Carried forward

The question "what is my access pattern, and does the model make it a scan, a join, or a traversal" is the thing I actually reuse, and it applies well outside databases.