Posts in "programming"

TIL UUIDv4 vs UUIDv7

I’ve always run with UUID v4 because it’s the default for the Ecto.UUID library in Elixir. However a coworker recommended UUID v7. Having never really looked into UUID other than to implement as a primary key the distinction was news to me.

Effectively;

  • UUID v4 is a totally random hash that is generated and extremely unlikely to ever conflict with any other generated UUID.
  • UUID v7 also contains a random hash but is also based on a timestamp, this means you can sort them and index them.

For further reference, yes there are UUIDs v1-v8 as of this writing. If you want a good description of each you can check out this helpful link .

TIL INSERT INTO with SELECT constraints

In the past month I’ve had to write a lot of SQL to migrate a system and split existing “locations” into tenants ie. migrating data from a public schema to a tenant’s schema is gets messy due to foreign key constraints. Order of operations is important but sometimes you still find yourself in a corner.

In instances where I already have data in the tenant schema, for example customers and I need to load a subset of data from another table, eg. customer_addreses it’s possible to run the query with tenant.customers as a constraint for what your inserting:

INSERT INTO tenant.customer_addresses SELECT * FROM public.customer_addresses AS pc WHERE EXISTS (SELECT 1 FROM tenant.customers AS tc WHERE tc.id == pc.customer_id)

This will insert public.customer_addresses into tenant.customer_addresses for every teant.customer that already exists. I’ve gotten around a lot of tricky constraint issues with missing/incomplete data this way.

Today I Learned ~D[2024-01-03]

You can use Erlang’s tc function to see how many microseconds a function takes. For example, say you were curious if Enum.filter/2 or Kernel.--/2 took longer:

Example:

$iex> vals = [1, 2, 3, 4, 5]
$iex> :timer.tc(Enum, :filter, [vals, &rem(&1, 2) == 1])
{20, [1, 3, 5]}

$iex> :timer.tc(Kernel, :--, [vals, [2, 4]])
{3, [1, 3, 5]}

Kernel.-- or vals -- [2, 4] took 3 micro seconds while Enum.filter/2 (Enum.filter(vals, & &1rem(&1, 2) == 1)) took 20.

This is a fairly trivial example but I could see this coming in handy with larger operations. For more detailed analysis you can always use Benchee. Thanks to chriserin for helping me get the right Erlang syntax for tc