Surrogate Keys and Natural Keys

A customer code arrives, and tomorrow the source system changes it. Surrogate keys give a warehouse its own stable row identity while natural keys keep the link to the source. Both keys have work to do, especially when history matters.

A dog with a plain brass tag on its collar sitting beside a pile of older collars in different colors and sizes.

Give Surrogate Keys and Natural Keys Separate Jobs

A natural key comes from the business or source system, such as a customer code. A surrogate key is generated by the warehouse for a dimension row. Facts reference the surrogate key so they can point to the right historical version of a member. The natural key remains necessary for matching new source data to existing members.

I ask who owns the source key and whether it can change or be reused. A key called permanent in a requirements document can still be recycled after a merger. The warehouse should not build its entire history on that promise alone.

Keep Source Identity Visible

Store source system identifier and natural key in the dimension, with appropriate uniqueness rules for active records. Two source systems can both have CustomerID 42, so a bare number is not globally unique. Normalize types and collations before matching. Keep the original value for traceability when a cleaned value is also stored.

I put the source key in load logs and reject reports. A fact that cannot find its dimension should not disappear silently. The source key is the bridge for diagnosis even when the report only displays a friendly name.

Use Surrogate Keys for History

In a Type 2 slowly changing dimension, a customer can have several rows with the same natural key and different effective periods. Each row gets a distinct surrogate key. A fact event uses the key for the version active at the event time. That preserves the attributes that were true when the fact occurred.

A natural key alone cannot distinguish those versions. I test a customer whose region changed between two orders. If both orders join to the newest region, the historical model has lost its purpose. Surrogate keys make the distinction explicit.

Create a Small Dimension

This example shows a surrogate identity key and source key with effective dates. It is a teaching shape, not a complete production dimension. Add a source system identifier when several sources share codes. Check that date periods do not overlap for one natural key during loading.

The unique constraint includes the start date to allow history. A separate filtered unique index can enforce one current row when the model has an IsCurrent flag.

CREATE TABLE dbo.DimCustomer
(
    CustomerKey bigint IDENTITY(1,1) NOT NULL
        CONSTRAINT PK_DimCustomer PRIMARY KEY,
    SourceCustomerID nvarchar(50) NOT NULL,
    CustomerName nvarchar(200) NOT NULL,
    EffectiveFrom datetime2(0) NOT NULL,
    EffectiveTo datetime2(0) NOT NULL,
    CONSTRAINT UQ_DimCustomer_Source_Start
        UNIQUE (SourceCustomerID, EffectiveFrom)
);
From a source code to the right version: a diagram about the surrogate keys

Resolve Keys During Fact Loads

A fact load uses the source natural key and event time to find the correct dimension row. Join on source key and a half-open effective interval. If no row matches, apply a documented unknown-member or reject policy. If two rows match, fail the load and repair overlapping dimension periods.

I count unmatched and multiply matched facts before insertion. A simple join that silently drops unmatched rows can make revenue disappear from reports. The query below identifies facts with no valid dimension version.

SELECT s.SourceCustomerID, s.SaleDate
FROM dbo.FactSaleStage AS s
LEFT JOIN dbo.DimCustomer AS d
  ON d.SourceCustomerID = s.SourceCustomerID
 AND s.SaleDate >= d.EffectiveFrom
 AND s.SaleDate < d.EffectiveTo
WHERE d.CustomerKey IS NULL;

Do Not Confuse Surrogate With Meaning

A surrogate key is an internal identifier. It should not encode region, status, or other business attributes. Those values change and belong in columns. An identity value can be narrow and efficient, but it does not prove uniqueness of a source customer. Enforce natural-key rules separately.

I keep the surrogate out of external contracts where possible. Sending it back to a source system can create a dependency on warehouse row versions the source does not understand. Use source identifiers for exchange and surrogate identifiers for warehouse joins.

Handle Natural-Key Changes

When the source corrects or replaces a natural key, decide whether the warehouse treats it as the same entity. Keep a crosswalk from old key to stable business identity if needed. Do not update every historical fact just because a code changed unless the business definition requires restatement.

I test a corrected customer code and a reused old code. Those cases reveal whether the lookup logic depends on a value that is not truly stable. Document the decision so future loads do not invent a second customer by accident.

Protect Lookup Performance for Surrogate Keys

Dimension lookups run for many staged facts. Index source system, natural key, and effective dates according to the load predicate. A Type 2 lookup can return several rows before the date filter narrows it. Check plans and row counts under a representative load. An index that helps lookup also adds cost to dimension updates.

The query below shows whether more than one dimension version claims the same source key and start time. It supplements, not replaces, the actual overlap test.

SELECT SourceCustomerID, EffectiveFrom,
       COUNT_BIG(*) AS version_count
FROM dbo.DimCustomer
GROUP BY SourceCustomerID, EffectiveFrom
HAVING COUNT_BIG(*) > 1;

Keep the Two Keys Together

Surrogate and natural keys are complementary. The surrogate gives a stable warehouse row identity. The natural key ties that row to a source and supports reconciliation. Effective dates and ownership rules complete the relationship. None of these columns should be added by habit without a clear load and report use.

Surrogate keys and natural keys work well when the team can trace a fact back to the source and still preserve history. The schema is correct when an old report can answer what was known then and a new load can find the right member now.

A fact load should resolve a natural key to exactly one valid surrogate key for the event date. A Type 2 dimension can hold several versions of the same natural key, so a join on the natural key alone can multiply facts. Add the effective date predicate and check for overlaps before publishing.

I keep an unknown member policy for facts whose dimension row has not arrived. The load can reject them or use a documented unknown surrogate key and later repair them. Silent NULL foreign keys make reports harder to reconcile. The natural key remains useful for matching source changes, while the surrogate key ties a fact to the intended historical version. Each key does a different job, and both should be visible in the load log.

When a customer attribute changes, which dimension version should an older sale still reference?

Related reading on this blog: What is Slowly Changing Dimension: Quiz: Puzzle: 31 of 31 and Lookups in a Data Load: Cached, Uncached and Wrong.

Two keys, two jobs: a checklist on the surrogate keys

A surrogate key is not a replacement for source identity, it is a stable identity for a warehouse row.

Published by Pinal Dave on SQLAuthority. More of my work at pinaldave.com.

Business Intelligence, Data Warehousing, Primary Key, SQL Constraint and Keys, SQL Server
Previous Post
Moving Averages in T-SQL
Next Post
SQL SERVER 2012 – DateTime Functions – DATEFROMPARTS() – DATETIMEFROMPARTS() – DATETIME2FROMPARTS()

Related Posts

Leave a Reply

Your email address will not be published. Required fields are marked *

Fill out this field
Fill out this field
Please enter a valid email address.