How to properly create composite primary keys - MYSQL
Master System Design with Codemia
Enhance your system design skills with over 120 practice problems, detailed solutions, and hands-on exercises.
Introduction
A composite primary key is a primary key made from more than one column. It is the right tool when row uniqueness comes from a combination of values rather than from a single identifier.
When a Composite Key Makes Sense
The classic example is a junction table in a many-to-many relationship. Suppose one student can enroll in many courses and one course can contain many students. The enrollments table is uniquely identified by the pair (student_id, course_id).
That is a natural composite key because neither column is unique by itself, but the pair is.
Creating the Table Correctly
In MySQL, define the participating columns first, then declare the composite primary key once:
This gives you two things:
- row uniqueness across the pair
- an index that starts with
student_idand thencourse_id
That second point matters for query performance.
Column Order Is Not Cosmetic
The order of columns in a composite primary key affects index usage. A primary key on (student_id, course_id) supports efficient lookups by:
- '
student_id' - '
student_idpluscourse_id'
It does not support the same efficient access pattern for queries filtering only by course_id.
If you often query by course first, add another index:
Do not assume the composite primary key automatically optimizes every access pattern.
Referencing a Composite Key
If another table needs to reference the composite key, the foreign key must include all key columns in the same order and compatible types.
This is where composite keys become slightly more verbose, but the model stays honest.
Composite Key Versus Surrogate Key
A common alternative is to add an auto-increment id column and put a UNIQUE constraint on the natural pair:
This version is often easier for ORMs and downstream foreign keys. The tradeoff is that the real business rule now lives in the unique constraint rather than in the primary key.
Neither design is universally better. Use a composite primary key when the combined columns are the real identity of the row and you are comfortable carrying them through relationships.
Updates and Stability
Primary keys should be stable. If one part of the composite key changes often, making it part of the primary key is usually a design smell because updates become more expensive and more relationships are affected.
That is a good litmus test:
- stable natural identity: composite primary key is reasonable
- frequently changing attribute: use a surrogate primary key instead
Common Pitfalls
The most common mistake is declaring multiple separate PRIMARY KEY clauses. A table can only have one primary key, even if that key spans multiple columns.
Another mistake is mixing column types across related tables. If the parent uses BIGINT UNSIGNED, the child should match exactly or foreign key creation may fail.
A third issue is ignoring index order. Developers often create (a, b) and later wonder why filtering only by b is still slow. That is expected behavior for composite indexes.
Summary
- Create composite primary keys with a single
PRIMARY KEY (col1, col2)clause. - Use them when row identity truly depends on a column combination.
- Remember that key column order affects index usefulness.
- Foreign keys must reference all composite key columns in matching order and type.
- Prefer a surrogate key when the natural key is large, awkward, or unstable.

