Skip to content

Latest commit

 

History

History
129 lines (91 loc) · 3.74 KB

README.md

File metadata and controls

129 lines (91 loc) · 3.74 KB

UUIDv7

CI Hex.pm Hex.pm Hex.pm

UUIDv7 for Elixir and (optionally) Ecto, using always-increasing clock-precision for monotonicity.

Uses suggestions described in Section 6.2 from RFC 9562 to add additional sort precision to a version 7 UUID.

When should I use this package?

  • You want sequential, time-based, ordered IDs (per-node).
  • You are willing to trade a small amount of raw performance for these guarantees.

NOTE: In this library, sequential UUIDs and ordering are more important than time precision and performance. We take a slight hit in both of those areas to ensure that the UUIDs are in order. For example, in the case of a backwards time leap, or even concurrent requests at the same time, we continue with the previously used timestamp and increment the clock precision by a minimum step.

When should I not use this package?

  • You don't care about sort/order precision beyond milliseconds.

There are other UUID packages, that only have millisecond precision, for example:

Installation

The package can be installed by adding uuid_v7 to your list of dependencies in mix.exs:

def deps do
  [
    {:uuid_v7, "~> 0.6.0"}
  ]
end

Usage

iex> UUIDv7.generate()
"018e90d8-06e8-7f9f-bfd7-6730ba98a51b"

iex> UUIDv7.bingenerate()
<<1, 142, 144, 216, 124, 16, 127, 196, 158, 92, 92, 74, 83, 46, 116, 173>>

Usage with Ecto

Use this the same way you would use Ecto.UUID. For example:

defmodule MyApp.Blog.Post do
  use Ecto.Schema

  @primary_key {:id, UUIDv7.Type, autogenerate: true}

  @foreign_key_type UUIDv7.Type

  schema "blog_posts" do
    field :text, :string
    # etc.
  end
end

To use UUIDs for everything in your migrations, it's easiest to just add that as the default type in your config. e.g.:

# config/config.exs
config :app, App.Repo,
  migration_primary_key: [type: :binary_id],
  migration_foreign_key: [type: :binary_id]

If you need to generate UUIDs in migrations (e.g. inserting or seeding data), then also add this to your Repo config as well:

# config/config.exs
config :app, App.Repo,
  start_apps_before_migration: [:uuid_v7]

Benchmarks

Run benchmarks with

MIX_ENV=bench mix run bench/filename.exs

Where filename.exs is the name of one of the benchmark files in the bench directory.

Compared to Uniq.UUID

(which has no extra clock precision, only millisecond precision.)

String:

Name                     ips        average  deviation         median         99th %
uniq v7 string        2.13 M      468.64 ns  ±4155.60%         417 ns         584 ns
uuid_v7 string        1.98 M      504.57 ns  ±3338.92%         458 ns         667 ns

Comparison:
uniq v7 string        2.13 M
uuid_v7 string        1.98 M - 1.08x slower +35.93 ns

Raw (binary):

Name                  ips        average  deviation         median         99th %
uniq v7 raw        3.14 M      318.58 ns  ±8234.89%         250 ns         417 ns
uuid_v7 raw        2.85 M      351.26 ns  ±4999.60%         292 ns         459 ns

Comparison:
uniq v7 raw        3.14 M
uuid_v7 raw        2.85 M - 1.10x slower +32.69 ns