skip to content

Schema Design & Normalization

How to shape tables, keys, and relationships so data stays consistent and queries stay sane — from normalization theory through ER modeling to evolving a live schema. This is the interview-heaviest relational area: almost every backend loop probes normal forms, M:N mapping, or a design trade-off.

part ofRelational database conceptsoverview, primer and where to startread it →
on this pageshow

explore

questions

94 · 4 sections

What does it mean for a table to be in first normal form, and what exactly does the requirement that values be 'atomic' rule out?

level: juniorimportance: must knowfreq 70%
basics
~20 s

A table is in first normal form when every column holds one single value of its declared type — no lists, no nested structures, no repeating groups such as phone1/phone2/phone3 — and every row is uniquely identifiable, normally by a primary key.

open as a page

Given a table ORDER_LINE(order_id, product_id, quantity, product_name, order_date) whose primary key is (order_id, product_id), does it satisfy Second Normal Form? Walk through your reasoning and the fix.

level: juniorimportance: must knowfreq 62%
basics
~10 s

No. product_name depends only on product_id and order_date only on order_id, both parts of the composite key, so both are partial dependencies. Split into ORDER(order_id, order_date), PRODUCT(product_id, product_name), and ORDER_LINE(order_id, product_id, quantity).

open as a page

You are shown EMPLOYEE(emp_id, emp_name, dept_id, dept_name, dept_location) with primary key emp_id. Is it in Third Normal Form, and how would you change it?

level: juniorimportance: must knowfreq 66%
basics
~10 s

No. dept_id determines dept_name and dept_location, so both depend on the key only through a non-key attribute. Split out DEPARTMENT(dept_id, dept_name, dept_location) and leave EMPLOYEE(emp_id, emp_name, dept_id) with a foreign key.

open as a page

Explain insertion, update, and deletion anomalies in a table that repeats the same fact across many rows, and give a concrete example of each.

level: juniorimportance: must knowfreq 65%
basics
~20 s

Repeating a fact means you cannot record it without an unrelated row (insertion anomaly), must rewrite every copy to change it (update anomaly, with drift if partial), and lose it when the last carrier row is deleted (deletion anomaly). Move the fact to its own table with a foreign key.

open as a page

What does Boyce-Codd Normal Form (BCNF) require of a table's functional dependencies, and what is a determinant?

level: juniorimportance: must knowfreq 50%
basics
~10 s

BCNF requires that for every non-trivial functional dependency X to Y in a table, X is a superkey. The determinant is X, the left-hand side. Nothing but a superkey may determine anything.

open as a page

In a conceptual data model, how do you decide whether something like a customer's address should be modeled as an entity in its own right or as an attribute of the customer?

level: juniorimportance: must knowfreq 55%
basics
~20 s

An entity is a thing with its own identity, its own describing facts and its own lifecycle. An attribute is one fact about a single entity instance. If addresses repeat, need describing, or are referenced on their own, model an entity.

open as a page

A model says a student may enrol in many courses and a course may hold many students. How is that many-to-many association represented in relational tables, what is the extra table's key, and why can it not be done with a column on either side?

level: juniorimportance: must knowfreq 70%
basics
~20 s

It becomes a third table holding one row per pair — student key and course key — with a foreign key to each parent and a primary key over the pair. Neither parent can hold the link because each side has many partners, and a column stores only one value.

open as a page

An entity in your model has an attribute that can hold several values at once, such as a customer's phone numbers. How is that mapped to relational tables, and why not use repeated columns or one comma-separated string?

level: juniorimportance: must knowfreq 50%
basics
~20 s

It becomes a child table holding the owner's key plus one value per row, with a foreign key to the owner and a key over (owner key, value). Repeated columns cap the count and scatter one fact; a delimited string loses typing, constraints and lookups.

open as a page

How do you store a tree structure (for example an organizational chart or a category tree) in a relational table using a self-referencing foreign key, and how do you retrieve a whole subtree from it?

level: juniorimportance: must knowfreq 72%
basics
~20 s

Give the table a parent_id column that is a foreign key back to its own primary key. Roots have NULL parent_id. One row per node stores one edge. To read a whole subtree you walk the parent_id chain repeatedly, which in standard SQL means a recursive query.

open as a page

How do you implement a many-to-many relationship between two tables in a relational database, and why can't a single foreign key column express it?

level: juniorimportance: must knowfreq 82%
basics
~20 s

Use a third table holding one foreign key to each side, keyed on the pair of them. A single foreign key column stores one value per row, so it cannot record many links from the same row.

open as a page

A table stores contact details as columns named phone1, phone2 and phone3. What problems does that layout cause, and what would you replace it with?

level: juniorimportance: must knowfreq 60%
basics
~20 s

Numbered columns hard-code a limit, force every query to repeat itself across all three columns, cannot be indexed or constrained as a group, and need a schema change to add a fourth. Replace them with a child table holding one row per phone, keyed to the parent.

open as a page

What is the difference between a natural primary key and a surrogate primary key, and how do you decide which to use for a table?

level: juniorimportance: must knowfreq 70%
basics
~20 s

A natural key is business data that already identifies the row (email, ISBN, country code). A surrogate key is a meaningless generated value (a sequence integer or UUID). Default to a surrogate for stability and narrowness, and keep the natural key as a UNIQUE constraint.

open as a page

What does it mean to "soft delete" a row in a relational database instead of issuing a DELETE statement, and what do you trade away by doing it?

level: juniorimportance: must knowfreq 60%
basics
~20 s

Soft delete marks a row as gone — usually by setting a deleted_at timestamp — instead of removing it. The row still physically exists, so it can be restored and still satisfies foreign keys, but every query must now filter it out and the table keeps growing.

open as a page

Your application must be able to answer "who changed this customer record, when, and what did it look like before?". What table design gives you that, and what belongs in each column?

level: juniorimportance: must knowfreq 50%
basics
~20 s

Add a history table that mirrors the live table's columns plus its own id, the changed row's id, changed_at, changed_by and the operation (insert/update/delete). Write one append-only row per change, inside the same transaction as the change.

open as a page

A team stores related rows across tables but declares no foreign key constraints, saying referential integrity is enforced in the application. What goes wrong, and when is skipping foreign keys actually defensible?

level: middleimportance: must knowfreq 60%
basics
~20 s

Application checks are racy and only cover the paths that implement them - backfills, admin tools and other services bypass them - so orphan rows accumulate silently. Foreign keys make the invariant unconditional. Skipping them is defensible mainly across separate datastores or shards, where the constraint is not expressible anyway.

open as a page

A team keeps its database schema in version-controlled migration scripts run by a tool such as Flyway or Liquibase. How does that tool know which scripts have already been applied to a given database, and what is recorded for each one?

level: juniorimportance: must knowfreq 68%
basics
~20 s

A history table inside the same database (Flyway's flyway_schema_history, Liquibase's DATABASECHANGELOG) holds one row per applied script: version or id, description, checksum, timestamp, success flag. Each run diffs the scripts on disk against those rows and applies only the missing ones.

open as a page

Walk through changing the representation of an existing column — for example splitting a single full_name column into first_name and last_name — on a busy production table with no downtime. What are the phases, and what must be true of the running application at each one?

level: middleimportance: must knowfreq 58%
basics
~20 s

Expand: add the new columns and make the app write both. Migrate: backfill existing rows in batches, then switch reads to the new columns. Contract: stop writing the old column and drop it. Every step must work with the previous version still running.

open as a page

A developer fixes a typo by editing a migration script that has already been applied to production and to several teammates' local databases. What goes wrong, and what should they have done instead?

level: middleimportance: must knowfreq 62%
basics
~20 s

The stored checksum no longer matches the edited file, so validation fails on every database that already ran it, while a fresh database gets the corrected version — the two diverge. Applied migrations are immutable: revert the edit and ship a new migration containing the fix.

open as a page

Which schema changes can block reads or writes on a large, busy table, and what techniques keep the lock window short enough to be invisible to users?

level: seniorimportance: must knowfreq 52%
basics
~20 s

Anything that rewrites the table or holds an exclusive lock: type changes, most index builds, validating new constraints, some column additions. Use concurrent or online index builds, add-then-validate constraints, a short lock timeout with retries, and batched work.

open as a page

A schema migration reaches production and turns out to be wrong. When is a scripted rollback actually a viable recovery, and when do you instead forward-fix by shipping a new migration?

level: seniorimportance: must knowfreq 55%
basics
~20 s

Rollback is viable only for additive, reversible changes that no code or data depends on yet — usually within minutes. Once a drop or a data transformation ran, or new code wrote data in the new shape, undoing loses information, so you forward-fix with a new migration and, if needed, roll back the application.

open as a page