Denormalization

Deliberately duplicating or precomputing data so reads get fast, accepting the chore of keeping the copies in sync.

store the count on the row so I don't count every timecopy it for speedduplicating data on purposecounter cachedenormalisationprecomputed columnflatten the tables so I stop joiningcached field on the record

See it

Live demo coming soon

What it is

Denormalization is breaking the one-fact-one-place rule on purpose, to buy read speed. The classic move is a counter cache: keep comments_count on the post instead of running COUNT(*) across a million comments on every page load. Same family: copying author_name onto the post to skip a join, storing a precomputed total on the order, or building a materialized view that flattens six tables into the shape your dashboard actually reads.

Reach for it when reads massively outnumber writes and you have measured the join or aggregate as the bottleneck, not guessed. Document-database and analytics designs lean on it heavily, since there is no cheap join to fall back on. Keep the normalized tables as the source of truth and treat every duplicated value as derived data you can rebuild from scratch.

The bill comes due on writes. Every copy is a thing that can drift, and drift is silent: nobody notices comments_count says 12 when there are 9. Update the copy in the same transaction as the source (or via a database trigger), never in scattered application code paths, and schedule a reconciliation job that recomputes the truth and reports mismatches. And check the cheap fix first: an index on a foreign key often erases the problem you were about to duplicate data over.

Ask AI for it

Denormalize [TABLE/QUERY] to speed up reads. Add a derived column [e.g. comments_count integer NOT NULL DEFAULT 0] to [PARENT TABLE], keeping the normalized child table as the source of truth. Maintain it with a database trigger on insert, update, and delete of the child rows so it cannot drift when new code paths appear, and write a backfill migration that computes the current values for existing rows. If the shape is more complex than a counter, use a materialized view with a refresh schedule instead. Add a reconciliation job that recomputes the derived values, logs any mismatch, and can repair them. Before writing any of it, show me the EXPLAIN ANALYZE for the current query and whether an index would solve it without duplication.

You might have meant

normalizationcachematerialized viewindexn 1 query

Go deeper