foundation

Foreign keys

Use referential integrity to protect relationships while understanding cascade behavior and migration constraints.

A foreign key declares that child column values must exist in a parent row (or be null if allowed). The database enforces referential integrity on insert, update, and delete — relationships are not only application convention.

					CREATE TABLE order_items (
  id        BIGINT PRIMARY KEY,
  order_id  BIGINT NOT NULL REFERENCES orders(id) ON DELETE RESTRICT,
  product_id BIGINT NOT NULL REFERENCES products(id)
);
				

| `ON DELETE` / `ON UPDATE` | Effect | |-----------------------------|--------| | `RESTRICT` / `NO ACTION` | Block parent change if children exist | | `CASCADE` | Propagate delete/update to children | | `SET NULL` | Null out FK when parent goes away |

`CASCADE` simplifies cleanup but can surprise you with deep trees and lock duration. `RESTRICT` surfaces orphan risk at delete time. Bulk loads and blue/green migrations may temporarily drop FKs — document the window and re-verify integrity after.

On interviews: explain why FKs belong in the schema for money and inventory domains, and when teams defer them (sharded writes, legacy ETL) with compensating checks.

Common pitfalls: missing indexes on FK columns (slow joins and lock checks); `CASCADE` chains that delete more than intended; app-only integrity that race under concurrency; adding FK to a dirty table without a backfill audit.

The trade-off is balancing database-enforced correctness against migration flexibility and cross-shard references — use FKs where a broken link is a production incident, not a logging inconvenience.

Checklist:

  • Name parent and child tables and cardinality.
  • Pick `ON DELETE` behavior explicitly.
  • Index every FK column used in joins.
  • Describe migration/backfill before enabling the constraint.
  • State what breaks if integrity is app-only.