SD System Design In Depth
0%
lesson system-designrelational-databasesdata-modeling

Relational database design

Module 2.1: Relational Modeling & Query Execution Updated Sep 17, 2026
📄 Cheat Sheet
Learn Database Normalization - 1NF, 2NF, 3NF, 4NF, 5NF
Decomplexify Learn Database Normalization - 1NF, 2NF, 3NF, 4NF, 5NF Watch on YouTube ↗

The clearest normal-forms walkthrough on YouTube: one running example, each anomaly shown concretely before the rule that fixes it.

0:00 / --:--

Under the Hood: Relational Invariants and Normal Forms

Relational database design is the discipline of structuring data into strongly typed tables governed by relational algebra. The core objective is eliminating data redundancy while enforcing integrity constraints directly at the storage engine level.

Relational Algebra: The Formal Foundation

Relational algebra is the mathematical framework behind every SQL query. When you write SELECT, WHERE, JOIN, or UNION, you are invoking operators defined by E.F. Codd (1970). Understanding these operators explains why certain query patterns are expensive and others are not.

OperatorSymbolWhat It DoesSQL EquivalentCost Implication
Selectionσp(R)Filters rows from relation R where predicate p is true.WHERE clauseO(N) full scan without index; O(log N) with B-Tree index.
ProjectionπA,B(R)Extracts only specified columns, discarding others.SELECT A, BReduces I/O if columns are in a covering index; otherwise requires heap fetch.
Cartesian ProductR × SEvery row of R paired with every row of S. Produces |R| × |S| rows.CROSS JOINExplosive row count: 1000 × 1000 = 1M rows. Almost always a bug in WHERE clause.
Natural JoinR ⋈ SCombines rows where columns with matching names are equal; eliminates duplicate columns.NATURAL JOIN / JOIN ... USINGNested loop: O(N×M). Hash join: O(N+M). Merge join: O(N log N + M log M).
UnionR ∪ SCombines all rows from R and S, removing duplicates.UNION (not UNION ALL)Deduplication requires sorting or hashing, adding O(N log N) overhead.
Set DifferenceR − SReturns rows in R that are not in S.EXCEPT / MINUSRequires scanning both relations; anti-join optimization in some engines.
AssignmentR ← SStores result of an expression into a named relation (view or temp table).CREATE VIEW / CTEViews are not pre-computed; CTE may be inlined or materialized by optimizer.

Key insight: SQL's declarative syntax hides these operators. When you write SELECT name FROM orders JOIN customers ON orders.cust_id = customers.id WHERE status = 'active', the optimizer translates it to: πname(σstatus='active'(orders ⋈cust_id=id customers)). The join algorithm (nested loop vs hash vs merge) determines physical performance; the algebra determines logical correctness.

Relational Normalization and Foreign Key Enforcement

erDiagram CUSTOMER ||--o{ ORDER : places ORDER ||--|{ ORDER_ITEM : contains PRODUCT ||--o{ ORDER_ITEM : references CUSTOMER { uuid id PK varchar email UK timestamp created_at } ORDER { uuid id PK uuid customer_id FK numeric total_amount varchar status } ORDER_ITEM { uuid id PK uuid order_id FK uuid product_id FK int quantity numeric unit_price }

Normalization vs. Selective Denormalization

1. The Three Normal Forms

  • First Normal Form (1NF): Atomic values; zero repeating column groups or comma-separated lists.
  • Second Normal Form (2NF): Must be in 1NF, and all non-key columns must depend on the entire primary key (eliminating partial functional dependencies in composite keys).
  • Third Normal Form (3NF): Must be in 2NF, and zero non-key columns may depend on other non-key columns (eliminating transitive functional dependencies).

2. The Cost of Normalization: The Multi-Join Penalty

While 3NF removes most update anomalies (BCNF closes the remaining gaps caused by overlapping candidate keys, and 4NF/5NF handle multi-valued and join dependencies), high-scale read queries (such as rendering an e-commerce order history page) require joining 6 or more tables. Each join traverses secondary B-Trees and random heap pages, consuming database memory buffers. High-throughput architectures use Selective Denormalization (e.g., storing a snapshot of product name and unit price directly on the order_items row) to turn multi-table joins into single-table lookups while preserving point-in-time order integrity.

Failure Modes and Edge Cases

  • Accidental Cartesian Product: Forgetting a JOIN condition produces |R| × |S| rows. A 10K × 10K join silently returns 100M rows, exhausting memory and causing OOM kills. Always verify row counts in query plans.
  • N+1 Query Problem: ORMs that lazy-load related entities inside a loop execute 1 query for the parent + N queries for children. For 10,000 orders with 3 items each, this becomes 10,001 queries. Fix with eager loading or batch joins.
  • Foreign Key Without Index: A foreign key column without an index forces a sequential scan of the child table on every DELETE (or key UPDATE) of a parent row, which is slow and holds row locks longer. Some engines (classically Oracle) also take a table-level lock on the unindexed child table. Always index foreign key columns.
  • Over-Normalization in OLTP: A fully normalized schema with 15+ joins per query may be theoretically elegant but causes multi-second read latency. Measure actual query plans before denormalizing.
  • NULL in UNIQUE Constraints: Most SQL engines (PostgreSQL, MySQL, Oracle) allow multiple NULLs in a UNIQUE column (NULL ≠ NULL in SQL), but SQL Server allows only one, and PostgreSQL 15+ can reject duplicate NULLs with UNIQUE NULLS NOT DISTINCT. Allowing multiple NULLs can cause unexpected duplicates in partial unique indexes.

Theoretical Framework: When to Normalize vs. Denormalize

The Codd's relational model (1970) and C.J. Date's database design principles advocate 3NF as the default to prevent update, insertion, and deletion anomalies. In practice, the decision depends on workload:

  • Write-heavy OLTP (banking, inventory): Normalize to 3NF. Update anomalies are costly; joins are affordable at small row counts with proper indexes.
  • Read-heavy OLAP (analytics, dashboards): Denormalize aggressively. Star schemas (Kimball methodology) trade write efficiency for query simplicity and scan performance.
  • Mixed workloads (e-commerce): Normalize the transactional core; denormalize into materialized views or separate read-optimized stores (e.g., Elasticsearch for product search, Redis for session data).
Check yourself Question 1 of 3
Forgotten join condition apply
From: Relational Algebra: The Formal Foundation

A report joins orders (20,000 rows) and customers (5,000 rows), but the ON clause was dropped during a refactor and nothing filters the result. How many rows does the query produce?

Key Takeaways

Relational design uses normalization (1NF, 2NF, 3NF) to eliminate update anomalies and enforce constraints.
Selective denormalization optimizes read-heavy queries by embedding immutable point-in-time attributes.
Foreign key constraints enforce referential integrity at the database layer, preventing dangling records.
Was this lesson helpful? Spot an issue or have a suggestion? Let us know on GitHub.
Report an issue