Database Design & Normalisation

Good schema design prevents bugs that are nearly impossible to fix later. A well-designed schema has no redundancy, enforces invariants at the database level, and makes queries natural to write.

Entity-Relationship (ER) Diagrams

Before writing SQL, model your domain with an ER diagram. Key elements:

  • Entity: a thing with independent existence — User, Order, Product
  • Attribute: a property of an entity — User.name, Order.amount
  • Relationship: how entities relate — User places Orders

Cardinality

RelationshipMeaningExample
One-to-One (1:1)Each row maps to at most one in the other tableUser ↔ Profile
One-to-Many (1:N)One row in A relates to many rows in BUser → Orders
Many-to-Many (M:N)Many in A relate to many in BStudents ↔ Courses

Converting ER to Tables

One-to-Many: put the foreign key on the "many" side.

sql
Loading...

Many-to-Many: create a junction table (associative entity).

sql
Loading...

One-to-One: foreign key on either side, with a UNIQUE constraint.

sql
Loading...

Functional Dependencies

A functional dependency A → B means: knowing A uniquely determines B. This is the basis of normalisation.

text
Loading...

First Normal Form (1NF)

Rule: every column holds an atomic value — no lists, arrays, or nested structures.

sql
Loading...

Second Normal Form (2NF)

Rule: 1NF + no partial dependencies — every non-key attribute depends on the whole primary key.

Only relevant when the primary key is composite.

sql
Loading...

Third Normal Form (3NF)

Rule: 2NF + no transitive dependencies — non-key attributes depend only on the primary key, not on other non-key attributes.

sql
Loading...

Boyce-Codd Normal Form (BCNF)

Stricter than 3NF: for every functional dependency A → B, A must be a superkey (uniquely identifies a row). Handles edge cases in tables with multiple candidate keys.

When to Denormalise

Normalisation removes redundancy but can require many joins for common queries, hurting read performance. Denormalisation deliberately re-introduces redundancy for speed:

sql
Loading...

Rules for denormalisation:

  1. Only after measuring that joins are actually slow
  2. Add write-side code to keep denormalised data in sync
  3. Document why the redundancy exists

Naming Conventions

Consistent naming makes a schema self-documenting:

ConventionExample
TablesPlural, snake_caseuser_orders
Primary keyidusers.id
Foreign key{table}_idorders.user_id
Timestampscreated_at, updated_at
Booleanis_ or has_ prefixis_active, has_verified_email

Key Takeaways

  • Model your domain in ER diagrams before writing SQL — entities, attributes, and relationships
  • 1:N relationships → foreign key on the "many" side; M:N → junction table
  • 1NF: atomic values. 2NF: no partial deps. 3NF: no transitive deps.
  • Normalise first; denormalise only when you've measured a real performance problem
  • Foreign key constraints enforce referential integrity at the DB level — don't skip them