Por que estes existem

O UUIDv4 aleatório é excelente em ser único e péssimo em ser ordenado, e essa desordem prejudica silenciosamente o desempenho do banco de dados (a história no artigo chaves de banco de dados). Antes de o UUIDv7 padronizar um UUID ordenado no tempo, vários projetos inventaram seus próprios formatos de identificador para obter o mesmo benefício: um ID que ordena por hora de criação, é compacto e amigável a URL, e ainda assim não precisa de coordenação central. Vale conhecê-los porque você os encontrará em sistemas reais e porque ilustram o mesmo punhado de compromissos.

A receita comum

Quase todo ID ordenável usa uma ideia: pôr um carimbo de tempo primeiro e bits aleatórios ou sequenciais depois. Ordenar os IDs como texto então os ordena aproximadamente por tempo, porque a parte mais significativa é o relógio. Codificar a coisa toda em uma base que preserva a ordem (de modo que o texto ordene da mesma forma que os bytes) torna os IDs lexicograficamente ordenáveis como simples strings. Os formatos diferem em quantos bits gastam com tempo versus aleatoriedade, em como codificam o resultado e em se precisam de qualquer coordenação entre geradores.

ULID

O é um identificador de 128 bits, a mesma largura de um UUID, renderizado como 26 caracteres em base32 de Crockford. Os primeiros 48 bits são um carimbo de tempo em milissegundos e os 80 restantes são aleatórios. A codificação não diferencia maiúsculas de minúsculas e foi escolhida para ser legível, e é lexicograficamente ordenável, com um modo monotônico opcional que garante a ordenação mesmo para IDs criados no mesmo milissegundo. O ULID (Identificador Universalmente Único Lexicograficamente Ordenável, do inglês Universally Unique Lexicographically Sortable Identifier) foi uma das respostas mais populares ao problema de ordenação do v4 e, sendo de 128 bits, pode ser armazenado no mesmo espaço de um UUID.

KSUID

O KSUID (da Segment) é um identificador de 160 bits codificado como 27 caracteres em base62. Ele usa um carimbo de tempo de 32 bits com resolução de segundos e uma época personalizada (de modo que seus carimbos de tempo permaneçam compactos por muitos anos) seguido de 128 bits de aleatoriedade. A porção aleatória maior torna as colisões extraordinariamente improváveis mesmo a altas taxas de geração, ao custo de ser mais largo que um UUID. Como o ULID, ele ordena por tempo quando ordenado como texto.

Snowflake

O Snowflake (originário do Twitter) é de outra forma: um inteiro de 64 bits, não um valor de 128 bits. Ele empacota um carimbo de tempo em milissegundos, um identificador de máquina ou de datacenter e um número de sequência por milissegundo em 64 bits, de modo que cabe em uma coluna bigint padrão com sinal. Essa compactação é seu apelo para conjuntos de dados muito grandes. O senão é a coordenação: todo gerador precisa de um ID de máquina único, que precisa ser atribuído e gerenciado, então o Snowflake troca a propriedade livre de coordenação dos UUIDs por um identificador bem menor. Muitos sistemas têm seu próprio esquema ao estilo Snowflake construído sobre a mesma ideia de empacotamento.

NanoID

O NanoID é o caso atípico: ele não é baseado em tempo de modo algum. É simplesmente uma string aleatória compacta e segura para URL com alfabeto e comprimento configuráveis, projetada como uma alternativa menor e mais amigável a um UUID aleatório quando você quer um identificador opaco em uma string curta. Compare-o ao UUIDv4 e não aos formatos ordenáveis: ele otimiza para tamanho e amigabilidade a URL, não para ordenação.

Como eles se comparam

Os compromissos se alinham ao longo de alguns eixos. Tamanho: o Snowflake é de 64 bits, o ULID e o UUID são de 128 bits, o KSUID é de 160 bits. Codificação: base32 (ULID), base62 (KSUID), um inteiro (Snowflake) ou hexadecimal (UUID). Coordenação: apenas o Snowflake precisa de IDs de máquina atribuídos; o resto é livre de coordenação. Ordenabilidade: todos exceto o NanoID são ordenados no tempo. E uma ressalva compartilhada: qualquer ID prefixado com carimbo de tempo torna sua hora de criação visível a qualquer um que possa lê-lo, o que é aceitável para a maioria dos usos, mas vale notar quando um identificador é exposto publicamente.

Por que o UUIDv7 mudou a conta

A razão pela qual esta lista importa menos do que importava é que o UUIDv7 (veja o artigo versões) padronizou a mesma receita de carimbo de tempo mais aleatoriedade dentro do formato UUID regular de 128 bits. Ele lhe dá ordenação no tempo e boa localidade de índice, ao mesmo tempo em que permanece um UUID padrão que todo banco de dados e biblioteca já entendem, sem codificação personalizada e sem coordenação. Então, para novos sistemas, o padrão honesto é recorrer primeiro ao v7 e usar uma destas alternativas apenas quando você precisar de sua propriedade específica: uma largura de 64 bits que cabe em um bigint (Snowflake), uma codificação de texto particular ou um espaço aleatório maior. Eles resolveram um problema real; o v7 agora resolve a maior parte dele em uma forma padrão.