Multi-tenacidade, bancos de dados, chaves primárias e ULID

ULID - DevSpace
ULID - DevSpace

Última atualização em 17 de novembro de 2025 por Willian Tuttoilmondo

Quando escrevi este artigo sobre multi-tenacidade, bancos de dados e chaves primárias, usei como exemplo um modelo que está disponível em quase todos os bancos de dados mais usados do mercado: o UUID. Como tudo evolui quando se fala em desenvolvimento e arquitetura, o UUID acabou revelando suas desvantagens e para que elas fossem superadas, outro modelo foi criado: o ULID. Mas, o que é o ULID e como usá-lo no meu dia a dia?

Desvendando o ULID

ULID, do Inglês Universally Unique Lexicographically Sortable Identifier, é um identificador único e ordenável formado por duas informações distintas: 48 bits que indicam os milissegundos de um Unix Epoch Timestamp e 80 bits de dados aleatórios, codificadas como uma string de 26 caracteres em Base32 Crockford, tornando-a mais compacta e eficiente para armazenamento e leitura do que um UUID tradicional. Num exemplo muito simpes, vamos criar sete identificadores ULID e ver como eles se ordenam.

ULID gerado em lote - DevSpace
ULID gerado em lote – DevSpace

Como é possível ver, todos os identificadores gerados exatamente no mesmo milissegundo possuem o mesmo início, o que nos permite ordenar o registro pelo momento de sua criação. Ao compararmos com o UUID veremos que essa vantagem não se mantém.

UUID gerado em lote - DevSpace
UUID gerado em lote – DevSpace

A primeira vantagem já se mostra aí. Enquanto o UUID não pode ser ordenado, o ULID nos permite fazer esta ordenação. Isso garante que os registros, independentemente da origem, possam ser visualmente ordenados pela chave primária quando nenhum outro ordenador for usado. Vale lembrar que, assim como o UUID, o ULID pode ser gerado pela aplicação.

A receita do bolo

A ideia por trás do ULID é simples: usar o momento da criação do valor para codificar seu valor. Os dez primeiros caracteres compõem a parcela codificada do timestamp do momento da geração. Por isso, no exemplo, como vários identificadores foram gerados no mesmo milissegundo, todos eles têm o mesmo início: 01K9SFSMXV. Vale lembrar que esta codificação é feita em Base32 Crockford, que utiliza apenas os caracteres 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, A, B, C, D, E, F, G, H, J, K, M, N, P, Q, R, S, T, V, W, X, Y e Z. Isso garante que o caractere O não seja confundido com o caracter 0, por exemplo. O restante, aleatório, é gerado da mesma forma, usando a mesma base.

O segredo, no entanto, está na codificação da data.

Para efetuarmos a codificação, vamos precisar definir duas constantes: um vetor com os caracteres permitidos e a largura deste vetor. Para isso, vamos defini-las da seguinte forma:

Depois disso, precisamos codificar o valor em uma string de 10 bytes com base no Unix Epoch Timestamp que definirmos como base. Para garantir a ordenação pelo horário da criação do valor, usaremos como base o valor de data e hora correntes.

Já para o restante, basta que usemos dados aleatórios determinados pela constante de caracteres válidos.

A desvantagem que temos, nesse caso, é que não existe uma estrutura nativa na linguagem Delphi – na verdade, em nenhuma linguagem de programação – que trate ULID. Para isso, precisamos criar uma estrutura e implementá-la. Para resolver esta questão, criei um tipo chamado TULID que cria e manipula ULIDs de maneira simples e rápida.

Implementando ULID no banco de dados

Assim como as linguagens de programação, os bancos de dados também não suportam nativamente o tipo ULID. Contudo, graças à comunidade, as plataformas livres vão sendo abastecidas com extensões que ajudam a tratar os dados de maneira simples e rápida.

Com gosto muito de usar o PostgreSQL para meus projetos, encontrei uma extensão muito boa, que me permite trabalhar com ULIDs de maneira simples e natural: a pgx_ulid. É ela quem me permite fazer o exercício lá do início, gerando as chaves em lote. Sua instalação é simples e rápida e pode ser feita tranquilamente. Como meu servidor PostgreSQL está instalado em uma máquina Linux, baixei o pacote para a versão do banco de dados – 18, no meu caso – aqui e fiz a instalação. Depois disso é só criar a extensão com o comando abaixo e voilà, teremos o tipo de dado e as funções básicas para operação disponíveis.

Isso cria as funções abaixo:

Funções PostgreSQL para ULID - DevSpace
Funções PostgreSQL para ULID – DevSpace

Para mais informações, a página do projeto no GitHUb conta com uma boa documentação.

Mas, enfim, quais são as vantagens mesmo?

Além da vantagem de ser uma chave única, como já vimos aqui, se compararmos com o UUID, temos o seguinte:

  • Classificável por tempo – Os primeiros 10 bytes contêm o Unix Epoch, que é classificado automaticamente;
  • Base32 de Crockford – Codificação mais eficiente, sem distinção entre maiúsculas e minúsculas, sem caracteres especiais;
  • Opção de monotonicidade – Pode gerar valores monotonicamente crescentes ou decrescentes para o mesmo timestamp e;
  • Legível por humanos – Mais fácil de depurar e ler em logs e bancos de dados.

Beleza, e agora?

ULID é algo novo e que muita gente ainda não conhece. Como sempre gosto de ressaltar, é importante ter em mente que, independente do projeto, as escolhas feitas no seu início determinam o rumo que ele toma e como podemos agir para ampliar e manter sua escalabilidade. Aplicar ULID em um novo projeto não requer muito, porém, na maioria dos casos, se a equipe não for madura o suficiente ou não estiver disposta a entender coisas novas, de nada adinatará.

Mas, confiem em mim quando digo, este é um caminho sem volta. Uma vez que dominamos essa técnica para criar chaves primárias e utiliza-las para manter nossos dados com chaves únicas, independente de sua origem, nunca mais usaremos sequences

 

Sobre Willian Tuttoilmondo 14 Artigos
Arquiteto de software com mais de 25 anos de experiência em desenvolvimento de software, especialista em desenvolvimento multicamadas utilizando Embarcadero Delphi e NodeJS para o back-end e o próprio Delphi para o front-end. Usuário Linux desde 1998, é evangelista PostgreSQL, banco de dados no qual é especialista. Ocupa hoje a posição de arquiteto de software na TOTVS, a maior empresa de tecnologia do Brasil, além de ser sócio fundador da LT Digital Labs, empresa especializada em desenvolvimento e treinamentos.

Seja o primeiro a comentar

Faça um comentário

Seu e-mail não será publicado.


*