UUIDs are fantastic for generating globally unique identifiers. But they’re terrible for databases when it comes to index locality and write performance — especially UUIDv4, which is fully random.
So what if we could combine the best of both worlds — randomness and sortability?
Meet COMB GUIDs — a clever hybrid used in enterprise systems to tame UUIDs without sacrificing performance.
🧬 What Is a COMB GUID?
COMB stands for Combined GUID (or "Combined Ordered GUID").
A COMB GUID is a UUID that embeds a timestamp — typically in the last few bytes — while keeping the rest of the identifier random.
> 📌 Origin: COMB was introduced by Jimmy Nilsson in 2004 to improve clustered index performance in SQL Server when using GUIDs.
⚙️ Why COMB GUIDs Matter
Traditional UUIDv4s are completely random. When used as a primary key:
- Index inserts are non-sequential
- Fragmentation increases
- Write performance drops (especially on clustered indexes)
COMB GUIDs solve this by:
- Keeping the randomness (for uniqueness)
- Injecting time information (for order-preserving inserts)
You get better B-tree locality and faster write performance, especially in relational databases like SQL Server, PostgreSQL, and MySQL.
🔢 COMB GUID Structure (Simplified)
UUID Segment | Purpose |
---|---|
First 10–12 bytes | Random |
Last 4–6 bytes | Encoded timestamp |
The exact layout varies, but the general idea is:
1. Generate a UUIDv4 or v1
2. Replace part of it (typically the tail) with a timestamp
3. Store it as a standard UUID
Because it’s still 128 bits, COMB GUIDs are fully UUID-compatible.
🧪 Implementing COMB GUIDs
🧠 Strategy:
1. Generate a UUIDv4
2. Get a timestamp (e.g. Unix time in milliseconds)
3. Inject the timestamp bytes into the UUID (tail or middle)
4. Return as a standard UUID object
Let’s look at language-specific implementations.
💻 C# Example (SQL Server + EF Core)
Entity Framework Core supports COMB GUIDs natively through value generation.
public class CombGuidGenerator
{
public static Guid NewComb()
{
var guidArray = Guid.NewGuid().ToByteArray();
var timestamp = BitConverter.GetBytes(DateTime.UtcNow.Ticks);
// Overwrite last 6 bytes with timestamp (little-endian safe)
Array.Copy(timestamp, 2, guidArray, 10, 6);
return new Guid(guidArray);
}
}
Use in Entity Framework:
builder.Property(x => x.Id)
.HasDefaultValueSql("NEWSEQUENTIALID()");
> SQL Server's NEWSEQUENTIALID()
is similar to COMB — with time-based ordering for clustered indexes.
🐍 Python Example
import uuid
import time
def new_comb_uuid():
u = uuid.uuid4()
now = int(time.time() * 1000)
ts_bytes = now.to_bytes(6, byteorder='big')
comb_bytes = u.bytes[:10] + ts_bytes
return uuid.UUID(bytes=comb_bytes)
# Example
print(new_comb_uuid())
> Modify the number of timestamp bytes depending on resolution needed (millis, micros, etc.)
☕ Java Example
import java.nio.ByteBuffer;
import java.util.UUID;
public class CombUuid {
public static UUID generate() {
UUID base = UUID.randomUUID();
long timeMillis = System.currentTimeMillis();
ByteBuffer bb = ByteBuffer.wrap(new byte[16]);
bb.putLong(base.getMostSignificantBits());
bb.putInt((int) (timeMillis >> 16));
bb.putShort((short) timeMillis); // Lower 2 bytes
bb.rewind();
long msb = bb.getLong();
long lsb = bb.getLong();
return new UUID(msb, lsb);
}
}
🧠 COMB vs UUIDv7
Feature | COMB GUID | UUIDv7 |
---|---|---|
Timestamp | Embedded manually | Built-in (RFC 9562) |
Randomness | Partial | High (74 bits) |
Standard-compliant | ✅ (RFC 4122) | ✅ (RFC 9562) |
Sortable | ✅ | ✅ |
DB compatibility | ✅ | ✅ (where supported) |
Summary:
- COMB: Custom hybrid, widely used in SQL Server, flexible placement
- UUIDv7: Modern, standardized, gaining adoption
🧰 When Should You Use COMB GUIDs?
✅ Use COMB GUIDs if:
- You’re using SQL Server, MySQL, or PostgreSQL with clustered indexes
- You need insert-time sortability
- You want UUID compatibility but better write performance
🚫 Avoid COMB GUIDs if:
- You need cryptographic or untraceable identifiers (timestamp leaks info)
- You’re in a system that already supports UUIDv7
🔐 Security Considerations
Because part of a COMB GUID is a timestamp:
- IDs can be sorted chronologically
- They may reveal timing patterns (e.g. user signups)
This is usually fine for internal use, but not ideal for public identifiers.
Final Thoughts
COMB GUIDs are a brilliant compromise — the randomness of UUIDs with the sortability of sequential keys.
They’re battle-tested in enterprise systems, help avoid index fragmentation, and slot neatly into existing UUID workflows.
If you’re struggling with UUIDv4 and database performance, COMB GUIDs might be the fix you didn’t know you needed.
⚙️ Hybrid identifiers: powered by math, optimized by time.