which key type fits which table
Choosing a primary key is one of the most consequential decisions in table design: a business natural key such as an email address or a product SKU carries meaning, an artificial surrogate key such as an auto-increment value or a UUID is stable and meaningless. This post compares both strategies concretely, presents composite keys as a third option, and delivers a practical decision guide.
Table of contents
- 1. What a primary key needs to guarantee
- 2. Natural keys: definition and examples
- 3. Advantages of natural keys
- 4. Disadvantages of natural keys
- 5. Surrogate keys: auto-increment vs. UUID
- 6. Advantages of surrogate keys
- 7. Disadvantages of surrogate keys
- 8. Composite keys: when they make sense
- 9. Decision guide and hybrid approach
- 10. Summary
- 11. FAQ
1. What a primary key needs to guarantee
A primary key has to guarantee three properties: uniqueness across every row in the table, stability across the entire lifetime of a record, and non-nullability, because a primary key must never be NULL. These three properties sound self-evident, but in practice they get violated regularly whenever a seemingly unique business value is chosen as a primary key that months later turns out to be changeable or not actually unique after all.
A fourth, often neglected property is minimality: a primary key should not contain more columns than are needed for unique identification. A composite key made of five columns, when three of them would already be enough for uniqueness, makes every referencing foreign key relationship unnecessarily complex and every query harder to read, without delivering any real safety benefit.
The central decision for every new table is whether the primary key should be a natural key, a meaningful value that already exists in the business domain, or a surrogate key, a meaningless value generated specifically for this purpose. Both strategies have their place, and the wrong choice often only reveals its consequences once the table is already used in production and changing the primary key triggers expensive migrations. This post works out the criteria for making that decision on solid ground.
This decision does not just affect the one table itself, it radiates out to every table that references it via a foreign key. Once chosen, a primary key typically gets repeated across dozens of other tables, each with its own indexes, its own JOIN conditions and its own foreign key constraints. This exact reach is what makes the choice so consequential: a mistake in a small reference table is easy to fix, a mistake in a central entity such as "customer" or "product" often triggers dozens of migration scripts in a grown system.
2. Natural keys: definition and examples
A natural key is an attribute, or a combination of attributes, that already exists in the real business domain and carries its own business meaning there. Typical examples of a primary key as a natural key are an email address for a user account, an ISBN for a book, a social security number for a person, or a SKU, a stock keeping unit, for a product. The appeal of a natural key is that it needs no extra column, the value already exists as a business-relevant attribute anyway.
These examples already show an important range: some natural keys, such as an ISBN, are assigned by an external institution and practically never change, while others, such as a SKU, are fully managed within your own organization and can be subject to internal reorganization at any time. This origin of the value is an important additional criterion when evaluating whether a candidate is viable as a primary key.
It is important to distinguish a genuine natural key from a value that merely appears unique by coincidence. With correct application logic an email address is truly unique system-wide and rarely changes, whereas a first and last name is neither unique nor stable and is therefore not a suitable primary key candidate. Checking whether a candidate really qualifies as a natural key has to consider the actual business reality, not just the current data set, in which no duplicates happen to exist.
A useful practical test: ask yourself whether the business side itself would ever change this value, for example as part of a correction, a rename, or a reassignment. If the answer can be "yes, theoretically", the candidate is risky for a stable primary key, even if a change seems unlikely in the current business process. This caution pays off especially for central entities that get referenced by many other tables.
3. Advantages of natural keys
The biggest advantage of a natural key as a primary key is semantic transparency: whoever sees a row with the key "978-3-16-148410-0" recognizes an ISBN immediately, while a surrogate key like "42" carries no business information whatsoever and always requires an extra look at another column or table. This readability significantly eases debugging, manual database queries, and communication between developers and the business side.
A second advantage is that a natural key as a primary key automatically enforces a UNIQUE constraint on a business-relevant attribute without adding an extra column and an extra index. Duplicates that are already forbidden in the business domain, such as two user accounts with the same email address, are thereby prevented directly at the database level, instead of relying solely on application logic, which could in theory be bypassed.
-- Natural key makes ad-hoc queries and manual debugging immediately readable
SELECT * FROM customers_natural WHERE email = 'anna.berger@example.com';
-- Result is self-explanatory: the key itself already identifies the row
-- Compare with a surrogate key, which needs an extra lookup for context
SELECT * FROM customers_autoincrement WHERE customer_id = 42;
-- customer_id = 42 says nothing on its own, a JOIN or second query is needed
4. Disadvantages of natural keys
The most serious disadvantage of a natural key as a primary key is a lack of stability. Values that seem immutable at the time of schema design frequently turn out to be changeable after all: an email address changes with a marriage or a job switch, a SKU gets reassigned during a product line reorganization. If such a value is the primary key, a change becomes an UPDATE that, through the foreign key relationship and unless ON UPDATE CASCADE is active, propagates to every referencing table, with considerable migration effort and a risk of inconsistency during the transition.
Even with ON UPDATE CASCADE active, a residual risk remains: cascading updates across many tables are expensive, long-running transactions that hold locks on a large number of rows and can thereby block concurrent write access. On a heavily trafficked table, a single update to a natural-key primary key can cause noticeable delays in live operation, a risk that simply does not exist with a stable surrogate key.
A second disadvantage is size and performance. Natural keys are often VARCHAR columns, which take up more storage than a compact integer, and indexes on VARCHAR columns are slower to search and join in many database engines than indexes on integer columns. In tables with many foreign key relationships, where the primary key gets repeated as a foreign key across numerous other tables, this storage and performance disadvantage adds up across the whole schema.
A third, less obvious disadvantage concerns international data: natural keys such as names often contain special characters, diacritics, or different character sets, which can complicate comparisons and sorting across locale settings. A numeric or purely alphanumeric surrogate primary key is fully independent of these collation questions, an often overlooked but relevant advantage in internationally used systems.
-- Natural key as primary key: readable, but changes ripple everywhere
CREATE TABLE customers_natural (
email VARCHAR(255) PRIMARY KEY,
full_name VARCHAR(150) NOT NULL,
registered_on DATE NOT NULL
);
CREATE TABLE orders_natural (
order_id INT PRIMARY KEY AUTO_INCREMENT,
customer_email VARCHAR(255) NOT NULL, -- FK repeats the wide VARCHAR key
order_date DATE NOT NULL,
FOREIGN KEY (customer_email) REFERENCES customers_natural(email)
ON UPDATE CASCADE -- required if the email can ever change
);
-- Problem: changing a customer's email now requires a cascading UPDATE
-- across every table that stores customer_email as a foreign key
5. Surrogate keys: auto-increment vs. UUID
A surrogate key is an artificially generated, business-meaningless value whose only job is to uniquely identify a row. The two most common implementations are an auto-increment integer, assigned sequentially by the database, and a UUID, a 128-bit value that can be generated with practically no collisions, often even client-side before the insert. As a primary key, both variants fully solve the stability problem of natural keys, because the value never carries any business meaning that could change.
The difference between auto-increment and UUID lies mainly in size, predictability and distributability. An auto-increment integer is compact, usually 4 or 8 bytes, and sorts itself automatically in insertion order, which keeps B-tree indexes efficient. A UUID needs 16 bytes, is not sequential, which can lead to index fragmentation on some database engines, but can be generated without consulting the database first, which makes UUIDs particularly attractive for distributed systems with several independent write nodes, where a central auto-increment counter would become a bottleneck.
A third, increasingly common option is time-sortable UUID variants, such as UUIDv7, which embed a timestamp into the leading bits. They combine generatability without central coordination with a largely sequential insertion order, significantly reducing the index fragmentation of classic, fully random UUIDs. For new schemas that need a primary key without a central issuing authority, such time-sortable variants are now often the better choice over classic random UUIDs.
-- Surrogate key with auto-increment: compact, sequential, index-friendly
CREATE TABLE customers_autoincrement (
customer_id INT PRIMARY KEY AUTO_INCREMENT,
email VARCHAR(255) NOT NULL UNIQUE, -- natural key kept as UNIQUE
full_name VARCHAR(150) NOT NULL
);
-- Surrogate key with UUID: generatable client-side, good for distributed writes
CREATE TABLE customers_uuid (
customer_id CHAR(36) PRIMARY KEY DEFAULT (UUID()),
email VARCHAR(255) NOT NULL UNIQUE,
full_name VARCHAR(150) NOT NULL
);
-- PostgreSQL: native UUID type plus gen_random_uuid()
CREATE TABLE customers_uuid_pg (
customer_id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
email VARCHAR(255) NOT NULL UNIQUE,
full_name VARCHAR(150) NOT NULL
);
6. Advantages of surrogate keys
The central advantage of a surrogate key as a primary key is absolute stability: because the value carries no business meaning, there is never a business reason to change it. If a customer's email address changes, customer_id stays untouched, and not a single foreign key relationship anywhere in the schema needs adjusting because of it. This decoupling of business reality from technical identity is the core reason surrogate keys are the default choice in most modern schemas.
This decoupling particularly pays off with privacy requirements: if an email address is anonymized or overwritten as part of a GDPR deletion request, the primary key customer_id stays unchanged, and historical order data referencing it via a foreign key remains referentially consistent. If the email address itself were the primary key, an anonymization would trigger a cascade of updates across the entire schema, an added risk precisely in an already sensitive operation.
This stability also eases working with external systems: if an external ID from a payment provider or a shipping interface is referenced, the mapping stays correct through the immutable surrogate primary key even when business attributes such as name or address change multiple times.
Another advantage concerns composite business keys: instead of repeating several columns for a composite natural key in every referencing table, a single integer or UUID foreign key is enough. This significantly simplifies JOIN conditions, from a multi-column ON to a single-column ON, and reduces the likelihood of mistakes when a developer forgets one of the several columns of a composite key during a JOIN.
7. Disadvantages of surrogate keys
The most obvious disadvantage of a surrogate key as a primary key is the loss of readability: a developer looking at a row with customer_id = 42 always has to run an extra JOIN or an extra query to find out which customer it is. In debugging sessions and manual database queries, this noticeably costs time compared to a self-descriptive natural key.
Views that enrich frequently needed foreign keys with the readable natural key can mitigate this disadvantage in practice without giving up the technical benefits of the primary key surrogate approach. Such a view combines the stability of the surrogate key in the schema with the readability of the natural key for everyday use, without developers having to manually look things up in every debugging session.
A second disadvantage concerns missing business uniqueness enforcement: a surrogate key alone does not prevent duplicates at the business level. Without an additional UNIQUE constraint on the email column, several customers with the same email address could be created despite a unique customer_id. Anyone choosing a surrogate key as a primary key must therefore consistently add a UNIQUE constraint on the actual natural key, or the original uniqueness protection is lost. With UUIDs, a third disadvantage is potentially worse index locality, since randomly distributed values can cause more page splits in a B-tree index than sequentially increasing integers.
A fourth, often overlooked disadvantage concerns security: sequential auto-increment values in publicly visible URLs, such as /orders/1042, leak information about the total number of records and invite systematic probing of neighboring IDs. UUIDs as a primary key avoid this problem because they are not guessable, but should not be mistaken as a substitute for real authorization checks, because security through unguessability alone is not full access control.
| Criterion | Natural key | Surrogate key |
|---|---|---|
| Stability | At risk, since business values can change | Stable, since meaningless and immutable |
| Readability | High, instantly interpretable in business terms | Low, needs a JOIN for context |
| Storage footprint | Usually larger, often VARCHAR | Compact, often 4 to 16 bytes |
| JOIN performance | Slower with VARCHAR comparisons | Faster with integer comparisons |
| Uniqueness enforcement | Automatic through the primary key itself | Only given with an added UNIQUE constraint |
8. Composite keys: when they make sense
A composite primary key consists of several columns that are unique together, even though no single column would be unique on its own. The classic use case is a junction table for an n:m relationship, where the combination of two foreign keys naturally defines the uniqueness of a row, for example member_id and book_id in a loans table, where a member cannot have the same book actively checked out twice at once.
Composite keys are often very meaningful in business terms, but share the disadvantages of natural keys once they get referenced as foreign keys in further tables: JOIN conditions become multi-column, and foreign key columns have to be repeated in equal number in the referencing table. In practice a good compromise is to keep the composite key as a UNIQUE constraint while the junction table additionally gets a single-column surrogate key as the actual primary key, once the relationship itself carries further attributes that justify its own identity.
A further argument for the single-column surrogate primary key in junction tables is compatibility with ORM frameworks and application layers, which frequently expect a single, simple ID per entity. A composite key can certainly be mapped directly in SQL, but requires extra configuration in many frameworks, which often offsets the seemingly purist advantage of a plain composite key in practical implementation.
-- Composite key as the natural choice for a pure junction table
CREATE TABLE book_tags (
book_id INT NOT NULL,
tag_id INT NOT NULL,
PRIMARY KEY (book_id, tag_id),
FOREIGN KEY (book_id) REFERENCES books(book_id),
FOREIGN KEY (tag_id) REFERENCES tags(tag_id)
);
-- Hybrid: surrogate primary key plus the composite kept as UNIQUE
-- useful once the relationship itself carries extra attributes
CREATE TABLE loans_hybrid (
loan_id INT PRIMARY KEY AUTO_INCREMENT,
member_id INT NOT NULL,
book_id INT NOT NULL,
borrowed_on DATE NOT NULL,
FOREIGN KEY (member_id) REFERENCES members(member_id),
FOREIGN KEY (book_id) REFERENCES books(book_id),
UNIQUE (member_id, book_id, borrowed_on)
);
9. Decision guide and hybrid approach
The most pragmatic strategy for most tables is a hybrid approach: a surrogate key as the technical primary key, combined with a UNIQUE constraint on the business natural key. This combination delivers stability for every foreign key relationship, because a value that is referenced in other tables never changes, while at the same time keeping the business uniqueness check on the natural key, so that no two customers can end up with the same email address.
A practical decision guide consists of three questions: does the business value ever change, even if rarely. Is the value referenced as a foreign key in many other tables. Does the value need to stay readable for manual queries and support cases. Two or more "yes" answers argue for the hybrid approach with a surrogate key as the technical primary key, while consistently stable, rarely referenced values remain defensible as a pure natural key too.
Pure natural keys as a primary key remain sensible for small, stable reference tables whose values are stable by definition, such as an ISO country code or a currency code. Pure surrogate keys without an accompanying UNIQUE constraint are almost always a mistake, because they lose the actual business uniqueness check. The decision should in every case be made table by table, not as a blanket project rule, because different entities have different stability and readability requirements.
-- The recommended hybrid approach as a complete, reusable pattern
CREATE TABLE products (
product_id INT PRIMARY KEY AUTO_INCREMENT, -- surrogate key for all FKs
sku VARCHAR(50) NOT NULL UNIQUE, -- natural key, enforced unique
product_name VARCHAR(255) NOT NULL,
unit_price DECIMAL(10,2) NOT NULL
);
-- Every referencing table uses the compact, stable surrogate key
CREATE TABLE inventory_movements (
movement_id INT PRIMARY KEY AUTO_INCREMENT,
product_id INT NOT NULL, -- stable, even if the SKU is ever reassigned
quantity INT NOT NULL,
moved_on DATE NOT NULL,
FOREIGN KEY (product_id) REFERENCES products(product_id)
);
-- Business logic can still look products up by SKU via the UNIQUE index
Mironsoft
Key strategy, schema design and migration consulting
Wrong primary key causing painful migrations?
We review existing schemas for unstable natural keys, design a clean hybrid approach, and plan the migration to surrogate keys without downtime.
Key audit
Check existing primary keys for stability risks
Migration plan
Step by step transition to surrogate keys with no data loss
Schema design
Hybrid approach with UNIQUE constraints for new tables
10. Summary
Choosing the right primary key strategy is not a matter of taste, it is a tradeoff between readability and stability. Natural keys such as email addresses or SKUs are immediately interpretable in business terms, but risk expensive migrations once the underlying business value changes after all. Surrogate keys such as auto-increment integers or UUIDs are absolutely stable, but lose all business meaning and must always be complemented with an additional UNIQUE constraint on the actual natural key.
The approach most commonly recommended in practice is the hybrid: a technical surrogate primary key for every foreign key relationship, combined with a UNIQUE constraint on the business natural key for business logic. Composite keys remain the right choice for pure junction tables without their own additional attributes. Every decision should be made table by table, based on the actual stability and uniqueness of the respective business value.
Primary key strategies: the essentials at a glance
Natural key
Readable in business terms, but risky on change. Suited for small, stable-by-definition reference tables.
Surrogate key
Stable and performant, but meaningless. Always combine with a UNIQUE constraint on the natural key.
Composite key
Ideal for pure junction tables. Often replaced by a surrogate key once extra attributes appear.
Recommendation
Hybrid approach as the default: surrogate key as primary key plus a UNIQUE constraint on the natural key.