Why Switching UUID Versions Can Boost Performance at Scale
Many teams choose UUIDs as primary keys to support distributed systems and avoid ID collisions.
But not all UUIDs are equal.
Some teams have seen 10รโ50ร performance improvements simply by switching from UUIDv4 to UUIDv7.
Sounds surprising?
Letโs break it down - step by step - with no hand-waving.
๐ฏ What This Blog Will Help You Decide
By the end, youโll understand:
- What UUIDv4 and UUIDv7 actually are
- How PostgreSQL indexes work internally
- Why random IDs hurt performance
- Why UUIDv7 scales dramatically better
- When you should (and shouldnโt) switch
- How to benchmark this yourself
1๏ธโฃ Quick Refresher: What Is a UUID?
A UUID (Universally Unique Identifier) is a 128-bit value designed to be globally unique.
Why developers use UUIDs:
- Safe for distributed systems
- Can be generated client-side
- No central ID generator
- Avoids ID collisions across services
PostgreSQL stores UUIDs efficiently (16 bytes), so UUIDs themselves are not slow.
๐ The problem is the insertion pattern, not the type.
2๏ธโฃ UUIDv4 - Random by Design
How UUIDv4 Works
UUIDv4 is purely random (122 random bits).
Example:
9f1c0d3a-4b6e-4b8f-8f91-17e0a0c9a721
e2a31f8b-91f2-4df7-98cb-6e9fcae721aa
0d2c5f99-5d8c-4b6d-8a0e-2dbbfa17d441
Key properties:
- No ordering
- No timestamp
- Completely scattered values
This randomness is great for uniqueness
โฆbut terrible for database indexes.
3๏ธโฃ UUIDv7 - Time-Ordered UUIDs
UUIDv7 is a newer standard designed specifically for modern databases.
How UUIDv7 Works
UUIDv7 combines:
- A timestamp (milliseconds) in the most significant bits
- Random bits for uniqueness
Example (simplified):
018f3b3a-9b5c-7d12-bc01-9a2cfe123456
018f3b3a-9b5d-7f44-a231-acde441298ab
018f3b3a-9b5e-82a1-9d22-acde112341aa
Key properties:
- Mostly increasing over time
- Still globally unique
- Still safe for distributed systems
๐ This ordering changes everything.
4๏ธโฃ How PostgreSQL Stores and Indexes Data (Critical Part)
PostgreSQL Table Storage
- Rows are stored in a heap
- Order in heap is not guaranteed
PostgreSQL Indexes
Primary keys use B-tree indexes by default.
5๏ธโฃ What Is a B-Tree (In Simple Terms)
A B-tree:
- Stores keys in sorted order
-
Is optimized for:
- Sequential inserts
- Range scans
- Cache-friendly access
Think of it like:
A well-organized book where new pages are best added at the end.
6๏ธโฃ Why UUIDv4 Hurts PostgreSQL Performance
With UUIDv4:
- Each new ID belongs somewhere random in the index
-
PostgreSQL must:
- Find the correct position
- Split pages frequently
- Rebalance the tree
- Touch random memory pages
Consequences:
- Heavy page splits
- Index fragmentation
- Poor cache locality
- Increased disk I/O
- Slower inserts
- Slower reads
- Slower vacuum
This gets worse as the table grows.
7๏ธโฃ Why UUIDv7 Is Fast
With UUIDv7:
- New rows are mostly appended
- Inserts hit the rightmost leaf page
- Minimal page splits
- Excellent cache locality
- Sequential disk writes
This is very similar to:
BIGSERIALIDENTITY- Snowflake-style IDs
๐ PostgreSQL loves this pattern.
8๏ธโฃ Why Teams See 10รโ50ร Improvements
At scale (millions of rows):
| Metric | UUIDv4 | UUIDv7 |
|---|---|---|
| Insert latency | High | Low |
| Index size | Large | Smaller |
| Cache efficiency | Poor | Excellent |
| Page splits | Frequent | Rare |
| Vacuum cost | High | Lower |
โ ๏ธ Important note:
- 50ร is workload-dependent
- Typical gains are 5รโ20ร
- Still very significant
9๏ธโฃ Hands-On Benchmark (You Can Try This)
Table Setup
CREATE TABLE test_uuid_v4 (
id UUID PRIMARY KEY,
data TEXT
);
CREATE TABLE test_uuid_v7 (
id UUID PRIMARY KEY,
data TEXT
);
Insert UUIDv4
INSERT INTO test_uuid_v4
SELECT gen_random_uuid(), 'data'
FROM generate_series(1, 1000000);
Insert UUIDv7 (Postgres 16+ or extension)
INSERT INTO test_uuid_v7
SELECT uuidv7(), 'data'
FROM generate_series(1, 1000000);
UUIDv7 generation requires Postgres 18 (
uuidv7()) or an extension such aspg_uuidv7in earlier versions.
Observe:
- Insert time
- Index size
- CPU usage
- Disk writes
Youโll see:
- UUIDv7 inserts are dramatically smoother
- Index size is smaller
- Less I/O pressure
๐ Why This Matters in Real Systems
Backend Impact
- Faster writes
- Better read performance
- Healthier indexes
- Lower infrastructure cost
Frontend Impact
- IDs sort naturally by creation time
- Easier pagination
- Better caching behavior
- Cleaner URLs
โ ๏ธ When UUIDv7 Is NOT the Right Choice
Be honest and balanced:
- If you need fully random IDs
- If timestamp leakage is a concern
- If your dataset is small
- If sequential IDs are unacceptable
UUIDv7 is a performance trade-off, not magic.
๐ Final Thoughts
This performance boost isnโt accidental โ itโs how databases work.
The takeaway:
- PostgreSQL B-trees love ordered inserts
- UUIDv4 is random โ bad at scale
- UUIDv7 is time-ordered โ excellent at scale
- Schema design decisions matter more than hardware
Choosing the right ID strategy early can save years of performance tuning later.
๐ฌ Have you used UUIDv4 in production and faced scaling issues?
Or already switched to UUIDv7?
Letโs discuss โ real-world experiences help everyone.
Top comments (0)