Skip to content
SimpleTools24

Should You Use a GUID as a Primary Key?

By SimpleTools24Published 4 min read

A GUID can be a good primary key when records are created in many places (several databases, offline clients, microservices) or when IDs must be generated before saving, because GUIDs don't clash and don't need a central counter. The main drawback is that random GUIDs (version 4) insert at random positions in an index, which causes page splits, fragmentation and poorer cache use as tables grow. Time-ordered GUIDs, such as UUID version 7 or SQL Server's NEWSEQUENTIALID(), keep most of the benefits while inserting in roughly increasing order.

Why People Choose GUID Keys

  • Generate anywhere. An app, a mobile client or a background job can create the ID before talking to the database.
  • No collisions when merging. Combining data from several databases or tenants is simpler when IDs are globally unique.
  • Non-sequential IDs in URLs. Random GUIDs don't reveal how many records exist or let users guess neighbouring IDs.
  • Simpler distributed systems. No coordination is needed between services to avoid duplicate IDs.

The Costs

Index Fragmentation

Databases usually store a primary key in a B-tree index, and in SQL Server and MySQL's InnoDB, the primary key also determines how table rows are physically ordered (a clustered index). With an auto-increment integer, new rows always go at the end. With random GUIDs, each insert lands somewhere random, so:

  • Pages fill up unevenly and split, leaving partly empty pages.
  • More of the index has to stay in memory, because inserts touch pages all over it.
  • Writes and reads can slow as the table grows large.

The effect is small for small tables and more noticeable for large, write-heavy ones.

Size

Key size comparison
Key typeStorageText form
INT4 bytesUp to 10 digits
BIGINT8 bytesUp to 19 digits
GUID / UUID (native type)16 bytes36 characters
GUID stored as text36+ bytes36 characters

The primary key is copied into every secondary index (in clustered designs) and every foreign key, so a 16-byte key adds up. Storing GUIDs as strings is the worst option: always use the native uniqueidentifier (SQL Server) or uuid (PostgreSQL) type, or BINARY(16) in MySQL.

Readability

3f2b8c1e-9d4a-4f6e-8b1a-2c7d5e9f0a13 is harder to read out over the phone or type into a support tool than 48213.

Sequential GUIDs and UUID v7

Time-ordered identifiers fix most of the fragmentation problem:

  • UUID v7 starts with a 48-bit Unix timestamp in milliseconds, followed by random bits. New values are larger than older ones (allowing for clock differences between machines), so inserts land near the end of the index. .NET 9's Guid.CreateVersion7(), PostgreSQL 18's uuidv7() and libraries in most languages generate it. UUID v4 vs UUID v7 compares them directly.
  • NEWSEQUENTIALID() in SQL Server generates increasing values on a given server for use as a column default. It's tuned to SQL Server's own GUID sort order. See how to generate a GUID in SQL Server.

One SQL Server caveat: its uniqueidentifier sort order compares the last bytes first, so a UUID v7 that's time-ordered as text isn't automatically ordered in a SQL Server index. Check how your library writes bytes for SQL Server.

The trade-off with time-ordered IDs is that they reveal approximately when a record was created, and IDs created close together are similar. For most applications that's acceptable; for some, it isn't.

Decision Guide

Choosing a primary key type
SituationGood choice
Single database, simple app, internal IDsAuto-increment integer
IDs created by clients or several servicesUUID v7 or sequential GUID
Merging data from multiple databasesUUID (v7 preferred for indexes)
Public IDs that mustn't reveal countsUUID v4, or integer key plus a separate public UUID
Very large, write-heavy tablesInteger or UUID v7; avoid random v4 as clustered key

A popular hybrid: an integer primary key for joins and indexing, plus a unique UUID column used in URLs and APIs. UUID vs auto-increment ID explores this pattern.

Trying the Formats

The GUID generator creates version 4 and version 7 GUIDs (as well as v1, v3, v5 and v6) in bulk, so you can see how v7 values share an increasing prefix while v4 values are scattered. That's a quick way to build test fixtures for comparing index behaviour in your own database.

Frequently Asked Questions

Are GUID primary keys slow?

Random GUIDs can be slower for large, write-heavy tables because of fragmentation. Time-ordered GUIDs reduce the problem considerably.

Should GUIDs be the clustered index?

Random GUIDs make poor clustered keys on large tables. Sequential GUIDs or UUID v7, or a separate clustered integer key, work better.

Can I switch from int to GUID keys later?

Yes, but it means migrating every foreign key. Many teams add a UUID column alongside the existing integer key instead.

Do GUIDs ever collide?

Properly generated random GUIDs have such a low collision probability that it isn't a practical concern.

Summary

GUID keys are great for distributed ID generation and merging, but random v4 values fragment indexes. Use UUID v7 or sequential GUIDs for keys, native 16-byte types for storage, and consider an integer-plus-UUID hybrid.

Sources