Why Random UUIDs Hurt Your Database and How UUIDv7 Solves It

Random UUID primary keys cause severe B‑tree write performance degradation due to low cache locality, while the new UUIDv7 format embeds timestamps for sortable, efficient inserts, and JDK 26 introduces a native API to generate them, offering a practical solution for Java back‑ends.

Selected Java Interview Questions
Selected Java Interview Questions
Selected Java Interview Questions
Why Random UUIDs Hurt Your Database and How UUIDv7 Solves It

Background: The Problem with Random UUIDs

Using UUID.randomUUID() as a primary key generates version‑4 random values that are not sortable. In large tables this leads to random B+‑tree insert locations, low cache hit rates, increased random I/O, index page splits, and overall write‑amplification.

Impact on Databases and Systems

Both MySQL InnoDB and PostgreSQL B‑tree indexes rely on data locality; random UUIDs break this expectation, causing frequent buffer‑pool churn and slower writes. Log and event systems also suffer because timestamps cannot be inferred from the ID, forcing extra created_at columns and additional indexes.

UUIDv7: Time‑Ordered Design

RFC 9562 (May 2024) defines several new UUID versions, with v7 being the most notable. It places a 48‑bit Unix‑millisecond timestamp in the high bits, followed by a 4‑bit version field (0111), a 12‑bit random segment (rand_a) for intra‑millisecond ordering, and a 62‑bit random segment (rand_b) for global uniqueness.

|<----------------------- 128 bits UUID ----------------------->|
|      48 bits      |4| 12 bits | 2 |      62 bits       |
| Unix timestamp ms|v| rand_a  |var|      rand_b        |

First 48 bits : Unix timestamp in milliseconds, valid until year 10889.

Next 4 bits : Fixed version field 0111 (v7).

Middle 12 bits (rand_a) : Optional monotonic counter or random value for ordering within the same millisecond.

Last 62 bits (rand_b) : High‑quality random bits ensuring global uniqueness.

JDK 26 Native API

JDK 26 adds a static factory method UUID.ofEpochMillis(long timestamp) that returns a UUIDv7. Example usage:

public static UUID ofEpochMillis(long timestamp) { /* native implementation */ }

UUID uuid = UUID.ofEpochMillis(System.currentTimeMillis());
System.out.println(uuid); // e.g. 0196c4e3-f8a1-7b2d-a3f0-1c9e4d7b3e2a

The method fills rand_a and rand_b with secure random numbers. The resulting UUIDs are sortable by creation time because the high bits encode the timestamp.

Monotonicity Caveat in High Concurrency

RFC 9562 requires UUIDv7 to be monotonically increasing on a single node, but JDK 26’s implementation does not guarantee this because rand_a is random. Two IDs generated within the same millisecond may compare out of order:

long now = System.currentTimeMillis();
UUID a = UUID.ofEpochMillis(now);
UUID b = UUID.ofEpochMillis(now);
System.out.println(a.compareTo(b)); // may be positive (a > b)

For most CRUD workloads this occasional inversion is negligible, but systems that rely on strict ordering (e.g., financial ledgers, pagination via WHERE id > last_id) need a custom monotonic generator. One approach is to maintain an AtomicLong that always returns a strictly increasing timestamp:

private static final AtomicLong lastTimestamp = new AtomicLong(0);
public static UUID generateMonotonicUUIDv7() {
    long now = System.currentTimeMillis();
    long ts = lastTimestamp.updateAndGet(prev -> Math.max(prev + 1, now));
    return UUID.ofEpochMillis(ts);
}

Comparison with Snowflake and ULID

Snowflake ID (Twitter, 2010) is a 64‑bit integer (41‑bit timestamp, 10‑bit machine ID, 12‑bit sequence). It is compact and naturally monotonic but requires a central node or pre‑allocated machine IDs and caps at 4096 IDs per millisecond.

ULID (128‑bit, 48‑bit timestamp + 80‑bit random) encodes in Crockford Base32, offering better readability than UUID but lacks an official RFC and has inconsistent language support.

UUIDv7 combines the benefits of standardization (RFC 9562), zero external dependencies, and native support in PostgreSQL 17 and upcoming MySQL 9.x. With JDK 26 you can generate it without third‑party libraries.

Choosing the Right Identifier

If you are in a pure Java ecosystem, do not need extreme storage efficiency, and your ID generation rate stays well below thousands per millisecond, UUIDv7 is the simplest choice. For high‑throughput financial systems, Snowflake’s 8‑byte integer remains the most cost‑effective. ULID is generally less recommended now that UUIDv7 offers comparable ordering with official standard support.

Adopting UUIDv7 in Existing Projects

New Projects : Switch JPA/Hibernate primary key type to UUID and configure the generation strategy to use UUID.ofEpochMillis(). Spring Boot 3.x and Hibernate 6.x already support the new format.

Legacy Data Migration : For tables with many foreign keys, run a transitional period where both old and new IDs coexist, updating associations at the application layer. Small tables (≤ 1 million rows) can be migrated in a single transaction after a backup.

Potential Pitfall : The first 48 bits expose the creation timestamp, which may be undesirable for public IDs (e.g., URLs). Consider this information leakage when designing external APIs.

Conclusion

Random UUIDs have long been known to degrade write performance. JDK 26 finally provides a native, standards‑based, time‑ordered UUIDv7 generator that can improve insert locality without adding external dependencies. For many Java back‑ends, adopting UUIDv7 is a low‑cost performance win.

Diagram
Diagram
Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

databaseUUIDID generationUUIDv7JDK26
Selected Java Interview Questions
Written by

Selected Java Interview Questions

A professional Java tech channel sharing common knowledge to help developers fill gaps. Follow us!

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.