Course contents
Practice
Questions where the answer is a judgement, not a return value. Try each one properly before opening the worked answer — the gap between your reasoning and the answer is the useful part.
2 questions
- 01core
A recipe app stores recipes with ingredients, steps and photos. Would you model it as documents or relations? What single new requirement would flip your answer?
Pick one, give the reasoning from the shape of the relationships, then name the requirement that would change your mind.
Show a worked answer
Documents, initially. A recipe is a genuine tree: its steps belong to it and nothing else, they are always read together with it, and they have no meaning outside it. Steps are ordered, and an array preserves that ordering for free where a relational schema needs an explicit
positioncolumn that everything must remember to sort by. You load a recipe whole and render it whole, which is exactly the case locality is good at.What flips it: ingredients becoming entities.
The moment someone asks for any of these —
- “show me every recipe using miso”
- “filter out recipes containing peanuts”
- “how much does this recipe cost at today’s prices”
- “convert all quantities to grams”
— an ingredient stops being a string on a recipe and becomes a shared record with its own allergens, price and density. Recipes then reference ingredients many-to-many with an edge that carries its own data (quantity, unit, preparation), which is a join table wearing a different hat.
The strongest single trigger is dietary filtering, because it is a query in the reverse direction — from ingredient to recipes — over data that must be authoritative rather than a free-typed string. “Contains peanuts” being wrong because someone typed “peanut” is not a formatting inconsistency.
A good answer names a trigger and explains it in terms of query direction. A weak answer picks a database and reasons from the database’s marketing.
The pragmatic real-world design, worth mentioning: relational recipes and steps, with ingredients as a proper table, and the rendered recipe cached as a document for reads. That is not fence-sitting — it is putting the authoritative model where correctness lives and the tree-shaped copy where the reads are.
- 02warmup
A page takes 4 seconds to load. The slow-query log shows no query over 3ms. Where has the time gone, and how would you confirm it?
Every individual query is fast and the page is slow. Explain the mechanism, then say how you would prove it rather than guess it.
Show a worked answer
It is almost certainly an N+1: hundreds of individually fast queries, executed in a loop, each paying a full round trip.
Four hundred queries at 3ms of database time plus 7ms of round trip is four seconds of page time and 1.2 seconds of query time — so the slow-query log, which only sees each statement in isolation, reports nothing wrong. Every component is behaving well; the composite is not, which is the same failure shape as the very first lesson in this course.
The reason it hides so well is that the join was never expressed. The database saw four hundred small correct queries and had no opportunity to plan one join, because nothing ever told it a join was wanted.
How to confirm it, in order of effort:
- Count the queries per request, not their durations. Most ORMs and APM agents will do this; a request that issues 400 statements is diagnosed already. This is the single most useful number and almost nobody logs it.
- Look at the shape of the log during one request. N+1 is visually obvious: the same statement repeated with a different parameter, hundreds of times in a row.
- Compare database time against wall time. 1.2s of query time inside a 4s request says the remainder is round trips and serialisation, not query execution.
The fix is to make the whole request one declarative statement — a join, or a single
INover the ids you collected — so the planner can see the shape of what you want. Most ORMs expose this as eager loading or an include.The wrong fix, worth naming because it is common: adding indexes. The queries are already 3ms. There is nothing to speed up. The problem is how many there are.