schema design
Constraints & Referential Integrity
Use NOT NULL, UNIQUE, CHECK, and FOREIGN KEY constraints so the database enforces invariants — instead of relying on every code path to do so.
A constraint is a rule the database itself enforces. It cannot be bypassed by any code that writes to the table.
A passport office: every field on the form must be filled, every reference number must match a real entry. The clerk doesn't trust you to remember.
Key Concepts
1
Why that matters more than it first appears. Data outlives the code that created it. Over a table's
life it will be written by the original service, a rewrite of that service, a batch import, a migration
script, and somebody at 2 a.m. fixing an incident by hand.
2
A rule living in one service's validation layer holds for that service. A rule in the schema holds for all
of them.
3
The five constraints.NOT NULL — a value must be present.
NOT NULL
4
UNIQUE — no duplicates in this column, or in this combination of columns. This is how you express an
alternate key such as an email address.
UNIQUE
5
CHECK — a rule about one row: price >= 0, or status IN ('active','closed').
CHECKprice >= 0status IN ('active','closed')
6
PRIMARY KEY — unique and not null together, giving the row its identity.
PRIMARY KEY
7
FOREIGN KEY — this value must exist in another table. You cannot create an order for customer 99 if
customer 99 does not exist.
FOREIGN KEY
8
What happens when the referenced row is deleted. A foreign key must say, and the choice has teeth:
9
ON DELETE RESTRICT refuse the delete while children exist (the safe default)
ON DELETE CASCADE delete the children too
ON DELETE SET NULL keep the children, blank the reference10
CASCADE is the one to be careful with. Deleting a customer can remove their orders, and the order lines
under those orders, and the shipments under those — one statement, a chain you did not picture. Use it
where the child genuinely has no meaning without the parent, and prefer RESTRICT elsewhere.
CASCADERESTRICT
11
Constraints and application validation are not competing. Validate in the application so the user gets
a clear message on the right field. Keep the constraint so the rule is still true when a script writes
directly. The application layer is for the message; the database layer is for the guarantee.
12
The costs, honestly. A foreign key costs a lookup on every insert and update, so bulk loads run faster
with them dropped and re-added — but you must re-add them, and validate. Foreign keys also force insert
ordering: parents before children. And an unindexed foreign key column makes deleting a parent scan the
child table, which is a common and easily missed cause of slow deletes.
13
What the interviewer is probing.1. "Why enforce constraints in the database rather than the application?" Probing: the
argument. Stalls: "The app is enough." Moves up: the database is the last line — several
applications, scripts and migrations touch the data, and only the constraint applies to all of them.
14
2. "What does ON DELETE CASCADE risk?" Probing: the hazard. Stalls: "Nothing." Moves up:
one delete silently removing a large subtree, which is why many teams prefer RESTRICT and an
explicit deletion path.
15
3. "What is the performance cost of a foreign key?" Probing: the trade. Stalls: "None."
Moves up: a check on every insert and update, and a lock on the referenced row — usually worth it,
occasionally not at very high write rates.
16
4. "Why does a unique constraint need an index?" Probing: the mechanism. Stalls: "It does
not." Moves up: uniqueness is enforced by a unique index, so the constraint creates one — which is
also why it costs on writes.