martinthenth

martinthenth

UUIDv7 - A UUID v7 implementation and Ecto.Type for Elixir - based on Rust

Hello everybody :wave:

Recently, some of my colleagues talked about database ids and uuids and their problems, and I remembered the pain of working with randomly distributed primary keys. They’re nice at first but then you have to index and order by a different field like created_at, while serial and bigserial already have an order and are indexed as the primary key.

UUIDv6, UUIDv7 and UUIDv8 are new standards to deal with issues found in UUIDv4 and earlier. I especially liked this post that analyzes the new standards: https://blog.devgenius.io/analyzing-new-unique-identifier-formats-uuidv6-uuidv7-and-uuidv8-d6cc5cd7391a

My favourite is UUIDv7 because they’re like UUIDv4 but the first characters are based on a millisecond timestamp; it seems like a very small change.

Elixir doesn’t have a common implementation of UUIDv7 yet, and Ecto is based on UUIDv4. So I decided to build one based on a Rust package crates.io: Rust Package Registry, which is relatively mature.

The new library is called UUIDv7 and is available on Hex UUIDv7 - Hex.

Because it’s based on Rust, the UUID generation is a whopping 72% faster than the default Ecto.UUID version 4 generator. NIFs are precompiled and generated for most platforms.

It’s easy to set up, you only have to change one line:

def App.Schemas.User do
  use Ecto.Schema
  @primary_key {:id, UUIDv7, autogenerate: true}
end

You can verify the UUIDs are ordered by running a small test:

uuid1 = UUIDv7.generate()
uuid2 = UUIDv7.generate()
uuid3 = UUIDv7.generate()
uuid4 = UUIDv7.generate()

assert uuid1 < uuid2
assert uuid2 < uuid3
assert uuid3 < uuid4

Though you may have to add Process.sleep(1) between the generations to skip one millisecond (UUIDv7 is based on milliseconds and ends with random bits)

Since the performance difference between Rust-based UUID generation and Ecto.UUID is so large, maybe it could be a motivation to write other more commonly used functions as NIFs from more compute-efficient languages?

You can check the benchmark here: UUIDv7 - Benchmark

GitHub: UUIDv7 - GitHub
Hex: UUIDv7 - Hex

Most Liked

martinthenth

martinthenth

Yup, UUIDv7 and Uniq are compatible because of the shared standard, but uniq is a bit slower because it’s 100% Elixir. It’s comparable with Ecto.UUID.

iex(1)> UUIDv7.generate()
"0188f846-191e-7f32-81f1-871f64b71d6b"
iex(2)> Uniq.UUID.uuid7()
"0188f846-1ae4-7205-8cf4-ac0be8a620a1"

Benchmark:

Name                     ips        average  deviation         median         99th %
uuidv7                1.75 M      570.22 ns  ±3940.19%         500 ns         667 ns
uniq (uuid v7)        1.07 M      937.20 ns  ±1852.78%         916 ns        1000 ns
ecto (uuid v4)        1.02 M      978.17 ns  ±1593.54%         958 ns        1042 ns

Comparison:
uuidv7                1.75 M
uniq (uuid v7)        1.07 M - 1.64x slower +366.98 ns
ecto (uuid v4)        1.02 M - 1.72x slower +407.95 ns
c4710n

c4710n

A quote from https://uuid7.com/

  • Concurrency and Distribution: In distributed systems, generating unique, sequential IDs can be a challenge. UUIDv7 can be generated concurrently across multiple nodes without the risk of collisions, making it suitable for distributed architectures.
sbuttgereit

sbuttgereit

New proposed standards. While it looks like UUID v6+ have made a lot of progress, they haven’t been adopted as standards yet: RFC 9562 - Universally Unique IDentifiers (UUIDs)

This isn’t to say that what ends up being adopted will be much different than has appeared in the various drafts, but for some the formality can matter.

As an aside, it looks like the scope of the proposed standard has expanded as they’ve progressed through the process to actually revising the UUID v1 through v5 standards as well: Revise Universally Unique Identifier Definitions (uuidrev)… the revisions to previous standards are very limited to doing things like correcting errata (unsurprisingly).

Where Next?

Popular in Announcing Top

danschultzer
None of the current solutions worked well for me, so I went ahead and built a user management system from scratch. This project took far...
548 29377 241
New
mischov
import Meeseeks.CSS html = HTTPoison.get!("https://news.ycombinator.com/").body for story &lt;- Meeseeks.all(html, css("tr.athing")) do...
New
josevalim
EDIT: since Ecto 3.0 final version is out, this post was amended to use the final versions in the instructions below. Hi everyone, We a...
New
Crowdhailer
I have been updating a library that allows you to pipe between functions that use the erlang result tuple convention. Assuming you have ...
New
aesmail
Hello guys, I have finally made it. I created an admin interface for a framework. It’s been on my todo list for years and with the curre...
New
woutdp
Hi! I wanted to introduce my latest project LiveSvelte. It allows you to render Svelte inside LiveView with end-to-end reactivity. It’s ...
New
kelvinst
Hey everyone! Well, we made this lib a while ago and now we decided to finally go out and public with it! It’s a tool for creating and m...
New
grych
Hi folks, Few months ago I have announced the proof-of-concept of the library to manipulate the browsers DOM objects directly from Elixi...
639 52341 488
New
sbs
Only 650 LOC, wrote for fun :slight_smile: https://github.com/sunboshan/qrcode
New
marcuslankenau
I feel kind of stuck with the absence of a proper xml library for Elixir. Currently I use SweetXML which was ok for me more or less to pa...
New

Other popular topics Top

malloryerik
Hi, this is for people who, like me, have had some friction using .html.heex templates in VSCode. The solution seems to be, in a hyphena...
New
Harrisonl
We have an ECS cluster with 4 services, where each task joins a single cluster, via discovery ECS discovery service. Currently when I de...
New
joeerl
Hello again - after a longish gap I’ve decided I really must dig into Elixir and see what’s been happening here - so I have a few questio...
New
stefanluptak
Hello everybody, usually, I use a 29" ultra-wide monitor for VSCode which can easily accomodate explorer (files panel) + file with code ...
New
belgoros
I’m not a pro in using Regex and can’t figure out why the following behaviour happens, especially if we take into account the difference ...
New
KronicDeth
Elixir plugin for JetBrain’s IntelliJ Platform (including Rubymine) This is a plugin that adds support for Elixir to JetBrains IntelliJ...
289 36128 110
New
Brian
What is the proper way to load a module from a file in to IEX? In the python world, doing something like this pretty standard: from ....
New
AstonJ
Seen any cool LiveView demos, sample apps or examples? Please post them here! :003:
New
jononomo
For some reason my phoenix channels are working for me in my local dev environment, but as soon as I deploy via Docker, I get a 403 error...
New
lanycrost
Hi everyone! I need implement if…else if…else condition from my elixir code, and anymore of this control flow structures not work proper...
New

We're in Beta

About us Mission Statement