Surrogate Key vs. Natural Key in SQL Server: The Complete Guide
This is not a debate this guide is trying to settle, because it is not actually one debate. “Surrogate or natural key” is really three separate, mostly independent questions bundled into one sentence: what identifies a row uniquely to the business, what generates that identifier, and what SQL Server should physically cluster the table on. Most of the strong opinions on this topic come from answering only one of those three questions and assuming it settles all three. It does not, and SQL Server’s own documented internals explain exactly why.
What this guide covers: the mechanical differences between IDENTITY and SEQUENCE as surrogate key generators, a documented gap-on-restart behavior worth knowing before it causes a support ticket, why a random GUID clustering key is a genuinely different problem from a narrow integer one, the real case for natural keys that surrogate-only design can silently miss, and where this site’s existing data warehouse coverage already answers the dimensional-modeling version of this question.
- Definitions: Three Different Questions
- IDENTITY vs. SEQUENCE: Generating the Surrogate
- The IDENTITY Gap-on-Restart Behavior
- The Real Question: What Should the Clustering Key Be
- The GUID Trap: uniqueidentifier as a Clustering Key
- The Case for Natural Keys
- Composite and Wide Keys: The Foreign Key Propagation Cost
- Where This Site Already Covers the Dimensional Modeling Angle
- A Practical Decision Framework
- Key Takeaways
- References
1Definitions: Three Different Questions
| Question | What it is actually asking |
|---|---|
| What uniquely identifies this row to the business? | The natural key question. An order number, a national ID, an email address, a composite of columns that together are unique in the real world. |
| What value does SQL Server generate to identify this row internally? | The surrogate key question. Typically an IDENTITY column, a SEQUENCE-populated column, or a uniqueidentifier. |
| What should the table physically be sorted by on disk? | The clustering key question. Independent of the first two; a table can be clustered on its surrogate key, its natural key, or neither. |
A table can have a surrogate primary key and still enforce a natural key with a separate unique constraint. A table can be clustered on something that is neither its primary key nor its most natural business identifier. Conflating these three questions into “surrogate versus natural” is where most of the internet-forum-grade advice on this topic goes wrong.
2IDENTITY vs. SEQUENCE: Generating the Surrogate
SQL Server has offered two genuinely different mechanisms for generating a surrogate value since SEQUENCE was introduced in SQL Server 2012.
| Property | IDENTITY | SEQUENCE |
|---|---|---|
| Scope | A column property, tied to one table | A standalone schema-bound database object, shareable across multiple tables |
| Value generation | Only on row insert | On demand, via NEXT VALUE FOR, independent of any insert |
| Maximum value | Bounded by the column’s data type; not separately configurable | Explicitly configurable with MAXVALUE |
| Cycling | Not supported | Supported with CYCLE |
| Cache control | Effectively on/off only, via database-scoped configuration or trace flag; no tunable cache size | Configurable cache size at creation |
Neither is meaningfully faster than the other for the vast majority of real workloads; the choice is rarely a performance decision on its own. SEQUENCE earns its place specifically when multiple tables need coordinated, non-overlapping identifiers, or when a value is needed before the row it belongs to is actually inserted.
3The IDENTITY Gap-on-Restart Behavior
This is a documented, specific behavior worth knowing before it surfaces as an unexplained gap in production data. Confirmed directly from Microsoft’s own ALTER DATABASE SCOPED CONFIGURATION reference: SQL Server caches a block of identity values in memory to reduce transaction log writes, and only logs the maximum value of that cached block, not every individual value. If the server restarts unexpectedly or fails over before that cached block is exhausted, the remaining cached values are discarded, and the next insert continues from the last logged maximum, not the last value actually used. The result is a visible gap.
The gap size is consistent and well documented across multiple independent sources: up to 1,000 for an int identity column, and up to 10,000 for a bigint identity column.
| Version | Control mechanism | Scope |
|---|---|---|
| SQL Server 2012 and later | Trace flag 272 | Instance-wide; cannot be scoped to a single database |
| SQL Server 2017 and later | ALTER DATABASE SCOPED CONFIGURATION SET IDENTITY_CACHE = OFF | Per-database |
This is a trade-off, not a free fix. Microsoft’s own documentation states plainly that identity caching improves insert performance on tables with identity columns. Disabling it removes the gap risk at the cost of that performance benefit. For most applications, an occasional gap in a surrogate key is harmless, since the surrogate was never meant to carry business meaning in the first place; disable caching only where contiguous values are a genuine, specific requirement.
4The Real Question: What Should the Clustering Key Be
Confirmed directly from Microsoft’s own current Index Architecture and Design Guide, a clustered index key has a defined set of desirable properties, and satisfying more of them makes every nonclustered index on the same table more efficient too, since the clustering key is carried inside every nonclustered index as its row locator.
Microsoft’s own documentation states the exact byte comparison directly: an int column uses 4 bytes, a bigint column uses 8 bytes, and a uniqueidentifier column uses 16 bytes. A clustering key populated by an IDENTITY clause or a sequence-backed default, on a single non-nullable int or bigint column that is never updated after insert, satisfies the narrow, static, and ever-increasing properties by construction. Microsoft’s documentation states this directly, and notes the contrasting case explicitly: a uniqueidentifier clustering key is wider by design, and does not satisfy the ever-increasing property at all unless its values are generated sequentially.
The specific terminology “narrow, static, unique, ever-increasing” traces most directly to Kimberly Tripp, a former Microsoft engineer and long-time SQL Server internals authority, whose detailed public explanation of this exact framework predates and underlies much of the community guidance still repeated on this topic today.
5The GUID Trap: uniqueidentifier as a Clustering Key
This is where surrogate key choice and clustering key choice most visibly collide, and where a genuinely large share of real-world SQL Server performance complaints originate.
A uniqueidentifier populated by NEWID() generates a value with no relationship to insertion order. Confirmed directly from Microsoft’s own NEWSEQUENTIALID documentation: NEWID() causes random activity, meaning each new row has to be inserted at a random point inside the existing B-tree rather than appended at the end, which is the direct mechanical cause of page splits and fragmentation.
-- Generates a page-split-prone clustering key
CREATE TABLE dbo.Orders (
OrderId uniqueidentifier NOT NULL DEFAULT NEWID() PRIMARY KEY CLUSTERED,
OrderDate datetime2 NOT NULL
);
NEWSEQUENTIALID() exists specifically to address this. Confirmed directly from Microsoft’s documentation: it helps completely fill data and index pages and is intended to reduce page splits and random I/O at the leaf level of an index, unlike NEWID().
-- Reduces page splits versus NEWID(), does not eliminate the width cost
CREATE TABLE dbo.Orders (
OrderId uniqueidentifier NOT NULL DEFAULT NEWSEQUENTIALID() PRIMARY KEY CLUSTERED,
OrderDate datetime2 NOT NULL
);
Two caveats Microsoft states directly, both worth knowing before relying on this function. First, NEWSEQUENTIALID() values are guessable, since they increase sequentially; avoid exposing them anywhere privacy or predictability is a concern. Second, and less commonly known: clusters of sequential values can develop, and the sequence can reset, when a database is moved to another computer, including on an Always On failover or an Azure SQL Database failover. A GUID clustering key generated this way is sequential only in the common case, not guaranteed sequential across every failure scenario a highly available environment will eventually hit.
NEWSEQUENTIALID() also narrows the fragmentation problem without touching the width problem. A uniqueidentifier clustering key is still 16 bytes, still four times the width of an int, and that width is carried inside every nonclustered index on the table as their row locator, regardless of which function generated the value.
6The Case for Natural Keys
Surrogate-only design has a real, specific failure mode that gets less attention than fragmentation: it can silently permit duplicate business entities. A table with only an IDENTITY primary key and no separate uniqueness constraint on the actual business identifier will happily accept two rows for the same customer, the same order number, the same account, because nothing in the schema says those two things cannot both exist. The surrogate key is unique by definition; that says nothing about whether the row it identifies is unique in the real world.
-- This schema allows duplicate customers with the same email,
-- because the surrogate key is the only thing enforced as unique
CREATE TABLE dbo.Customer (
CustomerId int IDENTITY(1,1) PRIMARY KEY,
Email varchar(256) NOT NULL
);
-- Adding the natural key as an explicit constraint closes that gap
-- without giving up the surrogate as the primary/foreign key value
ALTER TABLE dbo.Customer
ADD CONSTRAINT UQ_Customer_Email UNIQUE (Email);
This is not an argument against surrogate keys; it is an argument against treating the surrogate key as a substitute for actually modeling the natural key at all. The two are not mutually exclusive, and a well-designed table with a surrogate primary key usually still has one or more natural keys enforced as separate unique constraints.
7Composite and Wide Keys: The Foreign Key Propagation Cost
Whatever is chosen as a primary key gets copied into every child table that references it as a foreign key, and into every index that includes that foreign key column. A wide or composite natural key does not cost anything once; it costs that same width repeatedly, in every table and index downstream of it.
| Primary key choice | Cost carried into each child table |
|---|---|
int surrogate (4 bytes) | 4 bytes per row, per foreign key reference |
varchar(20) natural key | Up to 20 bytes per row, per foreign key reference, repeated in every child table and every index that includes it |
| Composite natural key (for example, three columns) | The combined width of all three columns, repeated the same way, plus a wider join predicate everywhere the relationship is queried |
This cost is real but is not automatically disqualifying. A natural key that is genuinely stable, reasonably narrow, and referenced by few child tables can be a perfectly reasonable clustering and even primary key choice. The propagation cost is the specific, concrete thing to weigh against the convenience of a natural key, not a blanket reason to avoid one.
8Where This Site Already Covers the Dimensional Modeling Angle
Everything in this guide addresses general OLTP schema design. Data warehouse and dimensional modeling design is a related but distinct question, already covered in depth elsewhere on this site: the DW/Lakehouse series covers surrogate key generation during Silver-to-Gold transformation, the requirement that surrogate keys be stable and integer-typed for join performance in columnar warehouses, and why SCD Type 2 dimensional models specifically require a surrogate key, since the same natural key legitimately needs multiple surrogate-keyed versions over time to represent history. That series is the reference for the dimensional modeling application of this topic; this guide does not repeat it.
9A Practical Decision Framework
| Situation | Reasonable default |
|---|---|
| Standard OLTP table, no cross-system identifier requirement | int or bigint IDENTITY surrogate, clustered on that surrogate, natural key enforced as a separate unique constraint |
| Identifier must be generated by a client or a distributed system before the row reaches the database | uniqueidentifier is often unavoidable; if it must be the clustering key, use NEWSEQUENTIALID() and accept the guessability trade-off, or cluster on a different narrow column and leave the GUID as a nonclustered unique key instead |
| Multiple tables need coordinated, non-overlapping identifier ranges | A shared SEQUENCE object rather than independent IDENTITY columns per table |
| The natural key is already narrow, stable, and rarely referenced by child tables | A natural key clustering strategy is a legitimate option, not just a theoretical one |
| Dimensional model, SCD Type 2 history required | Surrogate key is effectively required; see this site’s DW/Lakehouse series |
10Key Takeaways
- “Surrogate versus natural key” is really three separate questions: business uniqueness, value generation, and physical clustering. Answering one does not automatically answer the others.
- IDENTITY and SEQUENCE are mechanically different, not just stylistically different; SEQUENCE’s main advantage is coordinated values across multiple tables or generating a value before a row exists.
- Identity caching can produce gaps of up to 1,000 (int) or 10,000 (bigint) after an unexpected restart or failover; the fix (IDENTITY_CACHE, SQL Server 2017+, or trace flag 272 on older versions) trades away the performance benefit that caching exists to provide.
- Microsoft’s own documentation confirms the exact byte widths behind the clustering key argument: 4 bytes for int, 8 for bigint, 16 for uniqueidentifier, and confirms a uniqueidentifier clustering key does not satisfy the ever-increasing property unless generated sequentially.
NEWSEQUENTIALID()reduces page-split fragmentation versusNEWID()but does not remove the width cost, and Microsoft’s own documentation confirms its sequential guarantee is not absolute across every failover scenario.- A surrogate-only design without a separately enforced natural key can silently allow duplicate business entities; the surrogate and the natural key are not mutually exclusive and are usually both present in a well-designed table.
- The dimensional-modeling application of this topic, including why SCD Type 2 requires surrogate keys, is already covered in this site’s DW/Lakehouse series and is not repeated here.
The technical information in this article was verified against Microsoft documentation at the time of publication. SQL Server features, cloud service capabilities, licensing terms, and configuration requirements can change between versions and cumulative updates. Always validate implementation details against current Microsoft Learn documentation before deploying to production. References in this article link directly to the authoritative Microsoft sources.
References
- Microsoft Docs: SQL Server Index Design Guide (clustering key properties, exact byte widths)
- Microsoft Docs: NEWSEQUENTIALID (Transact-SQL)
- Microsoft Docs: ALTER DATABASE SCOPED CONFIGURATION (Transact-SQL), IDENTITY_CACHE option
- Microsoft Docs: CREATE SEQUENCE (Transact-SQL)
- Community and Industry Sources: Kimberly L. Tripp, “Ever-Increasing Clustering Key: The Clustered Index Debate…Again!” (SQLskills)
- SQLYARD: Microsoft Fabric: The Complete Guide — OneLake, Lakehouse, Pipelines, Medallion Architecture, and the Full Workshop
- SQLYARD: Understanding Heaps in SQL Server: Troubleshooting, Tuning, and When to Rebuild or Index
Discover more from SQLYARD
Subscribe to get the latest posts sent to your email.


