intermediate 2 min answer

A team proposes storing the customer's address on every order row "so order history is accurate". Is that denormalisation or a modelling error?

normalisationmodellinghistorytemporal
Show the full answer Hide the answer

The distinction that matters

It is neither, quite — it is a temporal modelling requirement being solved by accident.

Denormalisation duplicates a fact for performance, accepting an obligation to keep the copies in step. The team is not doing that. They are recording a different fact: not "where the customer lives" but "where this order was shipped". Those are genuinely different pieces of information that happen to have the same value at one moment.

Once framed that way, the design is obviously right and the justification is wrong. shipping_address on the order is not a stale copy of customer.address — it is the address used for that order, and it should never be updated when the customer moves.

Why the framing matters practically

Because it changes what you do next:

If it is a copy, you owe consistency: every writer must update all copies, and any missed path produces divergence. You would need a reconciliation job and you would treat a difference as a bug.

If it is a distinct fact, a difference is correct. No synchronisation, no reconciliation, and a job that "fixed" the divergence would be destroying data.

Getting this backwards is a recurring and expensive error. Teams have written jobs to "clean up inconsistent addresses" and destroyed the historical record of where things were actually shipped.

The general test

Ask what the field means, in a sentence, without referring to the other table. If you can — "the address this order was shipped to" — it is its own fact and belongs there. If you cannot — "the customer's current address, copied here for speed" — it is a cache, and it comes with obligations.

The same reasoning applies to price at time of sale, tax rate applied, product name on an invoice, and terms accepted at signup. All of these look like denormalisation and are actually point-in-time facts that must not change. This is the operational-store version of a Type 2 slowly changing dimension.

What a strong answer adds

Noting that where you do genuinely denormalise for performance, the obligation should be written down — which writer maintains the copy, and what reconciles it — because an undocumented cache in a schema is indistinguishable from a fact, and the next engineer will not be able to tell them apart.