SECTION 1
Historical Context & Motivation
Before the advent of the relational model, data was stored in flat files and hierarchical or network databases where relationships between records were encoded through physical pointers embedded in the storage layer itself. This tight coupling between logical meaning and physical representation made schema evolution painful and query formulation brittle. Edgar F. Codd's landmark 1970 paper, A Relational Model of Data for Large Shared Data Banks, proposed that data should be organized into relations (tables) and that integrity constraints—most notably primary and foreign keys—should be declared at the logical level, entirely independent of storage details.
The concepts of primary keys and foreign keys did not emerge in isolation. They grew from set theory and predicate logic, were refined through decades of academic debate, and were eventually codified in the SQL standard. Understanding their historical trajectory illuminates why modern relational databases enforce these constraints with such rigor—and why violating them produces the data anomalies that plague poorly designed systems.
1970 • Codd's Relational Model
1974 • System R & SEQUEL
1986 • SQL-86 (ANSI Standard)
1992 • SQL-92 & Cascading Actions
2003–Present • Modern Extensions
The central question these constraints address is deceptively simple: How do we guarantee that every row can be found unambiguously, and that references between tables always point to rows that actually exist? Primary keys solve the first half; foreign keys solve the second. Together, they form the backbone of referential integrity—the property that ensures a relational database never contains dangling pointers or orphaned records.
SECTION 2
Core Principles & Definitions
At the conceptual level, relational database design rests on a small set of well-defined constraints that govern how rows are identified and how tables reference one another. Before examining implementation details, it is essential to internalize the foundational ideas that make primary and foreign keys both necessary and sufficient for preserving data integrity across an entire schema.
Candidate Key
Primary Key
Foreign Key
Referential Integrity
Surrogate vs. Natural Key
KEY TAKEAWAY
Two additional properties merit attention. First, a primary key column (or set of columns) implicitly creates a unique clustered index in most RDBMSs, which accelerates lookups and joins. Second, foreign keys may allow NULLs—representing an optional relationship—unless the designer explicitly adds a NOT NULL constraint. Understanding these nuances prevents common schema-design mistakes that surface only under production workloads.
SECTION 3
Visual Explanation — Entity-Relationship Diagram
The most intuitive way to grasp primary and foreign key relationships is through a visual schema diagram. The following SVG depicts a simplified university database with four tables: students, courses, enrollments, and departments. Primary key columns are marked with a key icon, and foreign key arrows illustrate referential dependencies between tables.
enrollments uses a composite primary key (student_id, course_id), both of which are simultaneously foreign keys—a hallmark of associative (junction) tables.Several design decisions are visible in this diagram. The departments table sits at the top of the dependency hierarchy: it is referenced by both students and courses, but it does not itself reference any other table. This makes it a parent (or referenced) table. The enrollments table, conversely, is a child (or referencing) table that resolves the many-to-many relationship between students and courses by referencing both parent tables through its composite foreign-and-primary key.
SECTION 4
How Keys Work — Constraint Enforcement & Relational Algebra
While primary and foreign keys are most often discussed at the SQL syntax level, they have precise foundations in relational algebra and set theory. Understanding the formal underpinnings clarifies why certain design choices prevent anomalies and why the DBMS rejects specific operations at runtime.
Uniqueness & Entity Integrity
ENTITY INTEGRITY RULE
For a relation R with primary key attribute(s) K: no two distinct tuples may share the same key value, and no component of K may be NULL. This guarantees that every tuple is individually addressable.
Referential Integrity
REFERENTIAL INTEGRITY CONSTRAINT
For referencing relation S with foreign key FK referencing relation R's primary key PK: every non-NULL foreign key value must match exactly one primary key value in R. This is the formal definition of referential integrity.
DBMS Enforcement Points
The DBMS enforces these constraints at four critical operation points. On INSERT into the child table, the engine verifies that the foreign key value exists in the parent. On DELETE from the parent table, it checks whether any child rows reference the row being deleted—and applies the configured referential action (RESTRICT, CASCADE, SET NULL, or SET DEFAULT). On UPDATE of a parent's primary key, the same referential actions apply. Finally, on UPDATE of a child's foreign key, the engine re-validates the reference against the parent table.
Referential Actions Summary
SECTION 5
Choosing Primary Keys — Natural vs. Surrogate
Selecting the right primary key is one of the most consequential decisions in schema design. The choice affects storage overhead, join performance, migration complexity, and even business logic. Designers must evaluate every candidate key against a set of criteria before promoting one to primary key status. The two dominant strategies—natural keys and surrogate keys—each carry distinct advantages and risks that depend on the application domain.
Criteria for a Good Primary Key
- ✓ Uniqueness — the value must be distinct across all current and future rows in the table.
- ✓ Non-nullability — every row must have a value; NULLs are forbidden in primary key columns.
- ✓ Stability (Immutability) — the value should rarely, if ever, change. Updates to a PK cascade to every child table, which is expensive and error-prone.
- ✓ Simplicity — single-column keys are preferred over composite keys for join performance and readability.
- ✓ Compactness — smaller data types (INT, BIGINT) produce smaller indexes and faster comparisons than VARCHAR or UUID.
In practice, many designers adopt a hybrid approach: a surrogate integer or UUID serves as the primary key for efficient joins and stable references, while a UNIQUE constraint on the natural candidate (e.g., email or isbn) preserves business-level uniqueness. This "belt and suspenders" pattern is widespread in enterprise applications and ORMs like Hibernate and Django.
SECTION 6
Worked Example — Designing Keys for an E-Commerce Schema
Consider a simplified e-commerce application with the following business rules: customers place orders, each order contains one or more line items, and each line item references a product from the catalog. We will walk through the process of identifying candidate keys, selecting primary keys, and defining foreign key relationships.
E-Commerce Key Design
- 1
Step 1 — Identify Entities and Attributes
We identify four entities:customers(customer_id, email, name, address),products(product_id, sku, title, price),orders(order_id, customer_id, order_date, status), andorder_items(order_id, product_id, quantity, unit_price). The first task is to find candidate keys for each table. - 2
Step 2 — Determine Candidate Keys
Forcustomers, bothcustomer_id(surrogate) andemail(natural) are candidate keys—each uniquely identifies a customer. Forproducts,product_idandskuare both candidates. Fororders, onlyorder_idqualifies (customer_id is not unique across orders). Fororder_items, the composite(order_id, product_id)is a candidate key, assuming a product appears at most once per order.Candidate keys identified for all four tables. - 3
Step 3 — Select Primary Keys
We select surrogate keys forcustomersandproductsbecause emails can change and SKUs may be reformatted. We addUNIQUEconstraints onemailandskuto enforce business uniqueness. Fororders,order_id(auto-increment integer) is the primary key. Fororder_items, we choose the composite key(order_id, product_id).PKs: customers(customer_id), products(product_id), orders(order_id), order_items(order_id, product_id). - 4
Step 4 — Define Foreign Key Relationships
Now we encode the relationships.orders.customer_id→customers.customer_id(each order belongs to one customer).order_items.order_id→orders.order_id(each line item belongs to one order).order_items.product_id→products.product_id(each line item references one product).Three foreign key constraints defined, fully capturing the 1:N relationships. - 5
Step 5 — Choose Referential Actions
Fororders.customer_id, we choose ON DELETE RESTRICT—deleting a customer with existing orders should be blocked (data retention requirements). Fororder_items.order_id, we choose ON DELETE CASCADE—if an order is canceled and deleted, all its line items should be removed automatically. Fororder_items.product_id, we choose ON DELETE RESTRICT—we should not delete a product that appears in historical orders.Referential actions selected based on business rules: RESTRICT for data-preservation scenarios, CASCADE for dependent child data.
SECTION 7
Strengths, Limitations & Common Pitfalls
Primary and foreign keys are powerful tools, but they are not without trade-offs. Understanding both the strengths and the limitations of key-based integrity constraints helps designers make informed decisions, especially in high-throughput or distributed systems where enforcement costs are non-trivial.
| Aspect | Strengths | Limitations / Pitfalls |
|---|---|---|
| Data Integrity | Guaranteed at the database level—application bugs cannot create orphan rows or duplicate primary keys. | Enforcement has a performance cost: every INSERT, UPDATE, and DELETE triggers constraint checks and index lookups. |
| Query Performance | Primary keys automatically create clustered indexes; foreign keys hint the optimizer about join selectivity. | Wide composite keys increase index size and slow joins. FK constraints on high-velocity tables can become bottlenecks. |
| Schema Clarity | Keys serve as executable documentation of relationships—any developer can read the DDL to understand the data model. | Over-reliance on implicit conventions (e.g., always naming FK columns table_id) can mask semantic nuances. |
| Distributed Systems | In single-node RDBMS, FK enforcement is transactionally safe and atomic. | In sharded or microservice architectures, cross-shard FK enforcement is expensive or impossible; integrity must be managed at the application level. |
| Migration & ETL | Keys prevent accidental data corruption during migrations. | Bulk data loads often require temporarily disabling FK checks for performance, risking integrity if re-enabled without validation. |
Strengths vs. limitations of primary and foreign key constraints
DESIGN HEURISTIC
SECTION 8
Connection to Advanced Theory — Normalization & Beyond
Primary and foreign keys are not isolated concepts—they are the foundation upon which database normalization is built. Normal forms (1NF through BCNF and beyond) rely on the identification of functional dependencies, and a functional dependency X → Y is precisely the statement that X could serve as a determinant (superkey) for attribute Y. Decomposing a relation into higher normal forms often involves creating new tables linked by foreign keys that reference the original primary key.
| Concept | Introductory Level (This Lesson) | Advanced Theory |
|---|---|---|
| Key Selection | Choose a single stable attribute (or surrogate) as PK; apply UNIQUE to natural candidates. | Formal candidate key analysis via closure of functional dependencies; Armstrong's axioms for reasoning about key minimality. |
| Foreign Keys | Declare FK columns and referential actions (CASCADE, RESTRICT). | Inclusion dependencies, database schema graphs, and chase algorithms for testing lossless join decompositions. |
| Composite Keys | Used in junction tables to model many-to-many relationships. | Partial and transitive dependency analysis for 2NF and 3NF decomposition; multi-valued dependencies for 4NF. |
| Distributed Keys | Surrogate keys with auto-increment or UUID. | Snowflake IDs, CRDTs, vector clocks, and conflict-free replicated key generation in globally distributed databases. |
Conceptual keys in this lesson vs. advanced database theory
As you progress into courses on database internals, distributed systems, or data warehousing, you will encounter scenarios where traditional FK enforcement is relaxed for performance—star schemas in OLAP systems often omit FK constraints, relying on ETL pipelines for integrity. Even in these contexts, the conceptual notion of primary and foreign keys remains indispensable for understanding data lineage, designing efficient join paths, and communicating schema intent to other engineers.
SECTION 9
Practice Problems
Question 1: CONCEPTUAL
Show answer
Question 2: BASIC APPLICATION
books(isbn VARCHAR(13), title VARCHAR, author_id INT, publisher_id INT, pub_year INT), identify all candidate keys and recommend a primary key. Justify your choice using the criteria discussed in this lesson (uniqueness, stability, simplicity, compactness).Show answer
book_id SERIAL as the PK and place a UNIQUE constraint on isbn. This trades readability for a narrower, faster-joining integer key. The columns title and pub_year are not candidate keys because multiple books can share a title or publication year. The combination (title, author_id, pub_year) might be unique in practice but is fragile and overly wide for a PK.Question 3: INTERMEDIATE
users(user_id, username) and friendships(user_a_id, user_b_id, created_at). Design the primary key and foreign keys for friendships. Address the issue that friendship is bidirectional—should (Alice, Bob) and (Bob, Alice) both exist, or should the schema prevent duplicates?Show answer
user_a_id → users.user_id and user_b_id → users.user_id. For the primary key, (user_a_id, user_b_id) serves as a composite PK, preventing duplicate rows for the same pair. To prevent the bidirectional duplication problem, enforce a CHECK constraint: CHECK (user_a_id < user_b_id). This canonical ordering ensures each pair is stored exactly once. Alternatively, store both directions and use a surrogate PK, but this doubles storage and complicates deletion. The CHECK-constrained composite key is more space-efficient and semantically cleaner for undirected friendship graphs.Question 4: APPLIED
ON DELETE and ON UPDATE on each FK, and why?Show answer
patients(patient_id PK, name, dob), doctors(doctor_id PK, name, specialty), departments(dept_id PK, dept_name), appointments(appt_id PK, patient_id FK, doctor_id FK, dept_id FK, appt_date, notes), and patient_doctor_history(patient_id FK, doctor_id FK, start_date, end_date, PK(patient_id, doctor_id, start_date)). Referential actions: For appointments → patients, use ON DELETE RESTRICT (never delete a patient with medical history). For appointments → doctors, use ON DELETE SET NULL (if a doctor leaves, the appointment record survives with a NULL doctor_id for audit). For appointments → departments, use ON UPDATE CASCADE because department reorganizations should transparently update references. For patient_doctor_history FKs, use ON DELETE RESTRICT on both sides since historical records must be preserved for legal compliance.Question 5: CRITICAL THINKING
Show answer
SUMMARY
Lesson Summary
Summary
A primary key is the designated candidate key chosen to uniquely identify every row in a table. It must satisfy uniqueness and non-nullability, and it should ideally be stable, simple, and compact. Designers choose between natural keys (business-meaningful attributes) and surrogate keys (system-generated identifiers) based on the domain's stability and performance requirements.
A foreign key is a column (or set of columns) in a referencing table whose values must match the primary key of a referenced table, enforcing referential integrity. The DBMS provides referential actions (CASCADE, RESTRICT, SET NULL, SET DEFAULT) that govern what happens to child rows when a parent row is deleted or its key is updated. Together, primary and foreign keys form the backbone of relational database design, preventing orphan rows and dangling references, and they serve as the foundation for normalization and advanced schema analysis.