UUID v4 vs v7 vs ULID: Como Escolher o Identificador Certo para o Seu Banco de Dados
Voce esta iniciando um novo servico e a primeira decisao e enganosamente simples: como deve ser sua chave primaria? Inteiros auto-incrementais vazam contagens de linhas, expoem a ordem de criacao e quebram no momento em que voce precisa mesclar dados entre bancos de dados. UUIDs resolvem esses problemas — mas agora voce precisa escolher qual UUID.
O UUID v4 tem sido o padrao por mais de uma decada. O UUID v7, padronizado na RFC 9562 em maio de 2024, promete melhor desempenho em bancos de dados por meio de ordenacao temporal. E o ULID, a alternativa criada pela comunidade em 2016, oferece beneficios semelhantes em um formato mais compacto. Cada um tem compensacoes reais que afetam desempenho, privacidade e manutencao a longo prazo.
Este guia compara os tres — com dados reais de benchmark, conselhos praticos de migracao e um framework de decisao claro para 2026.
O Que e um UUID? (E Por Que “GUID” e a Mesma Coisa)
Um UUID (Universally Unique Identifier) e um valor de 128 bits projetado para ser unico sem uma autoridade central. O formato padrao sao 32 caracteres hexadecimais separados por hifens: 550e8400-e29b-41d4-a716-446655440000.
Se voce ja trabalhou com .NET ou Windows, ja viu esses identificadores chamados de GUIDs (Globally Unique Identifiers). Sao a mesma coisa — GUID e o nome que a Microsoft da ao padrao UUID. O layout dos bits, os algoritmos de geracao e os requisitos de armazenamento sao identicos.
O UUID passou por varias versoes. As que importam hoje:
| Versao | Estrategia | Padronizado | Ainda Relevante? |
|---|---|---|---|
| v1 | Timestamp + endereco MAC | RFC 4122 (2005) | Substituido principalmente pelo v7 |
| v4 | Aleatorio | RFC 4122 (2005) | Sim — o padrao atual |
| v5 | Baseado em nome (hash SHA-1) | RFC 4122 (2005) | Casos de uso especificos |
| v7 | Timestamp + aleatorio | RFC 9562 (2024) | Sim — a nova recomendacao |
A RFC 9562 e explicita sobre a direcao: “Implementacoes DEVEM utilizar UUIDv7 em vez de UUIDv1 e UUIDv6 se possivel.”
UUID v4: O Padrao Aleatorio
O UUID v4 gera identificadores a partir de 122 bits de aleatoriedade criptograficamente segura. Isso e um espaco de chaves de aproximadamente 5,3 x 10^36 valores possiveis — voce precisaria gerar um bilhao de UUIDs por segundo durante 86 anos para atingir uma probabilidade de colisao de 50%.
Como funciona: 128 bits no total, com 6 bits reservados para marcadores de versao (4) e variante. Os 122 bits restantes vem de um CSPRNG como crypto.getRandomValues().
Exemplo: f47ac10b-58cc-4372-a567-0e02b2c3d479
A simplicidade e sua forca. Nenhuma coordenacao necessaria, nenhum timestamp para vazar, nenhum estado para manter. Toda linguagem e banco de dados importante tem suporte nativo ao v4.
O Problema: UUIDs Aleatorios Fragmentam Seu Banco de Dados
A aleatoriedade pura tem um custo. Quando voce insere UUIDs aleatorios em um indice B-tree — o padrao para PostgreSQL, MySQL e a maioria dos bancos relacionais — novas linhas caem em posicoes arbitrarias na arvore. Isso causa:
- Divisoes de pagina: O banco de dados constantemente divide e reorganiza paginas do indice em vez de apenas anexar ao final.
- Amplificacao de escrita: Benchmarks da EnterpriseDB mostram que UUIDs aleatorios geram 8x mais WAL (write-ahead log) do que alternativas sequenciais — 20GB contra 2,5GB para a mesma carga de trabalho.
- Colapso de throughput: Em conjuntos de dados maiores que a RAM, insercoes com UUID aleatorio caem para 20-30% do throughput de UUIDs sequenciais.
- Desperdicio de espaco: A PlanetScale relata que UUIDs aleatorios fazem a utilizacao de paginas B+ tree do MySQL cair para ~50%, comparado a 94% com chaves sequenciais.
Isso nao e uma preocupacao teorica. A Buildkite viu uma reducao de 50% na taxa de WAL em seu banco de dados principal apos mudar para UUIDs ordenados por tempo. A Shopify mediu uma reducao de 50% na duracao de INSERT ao migrar de UUID v4 para identificadores ordenados por tempo nas chaves de idempotencia do sistema de pagamentos.
O UUID v4 e adequado para tabelas pequenas, escritas pouco frequentes ou qualquer lugar onde voce nao use o UUID como chave primaria. Para sistemas de alto throughput, o custo da fragmentacao se acumula ao longo do tempo.
UUID v7: Ordenado por Tempo e Amigavel ao Banco de Dados
O UUID v7 resolve o problema de fragmentacao colocando um timestamp primeiro. Os 48 bits mais significativos codificam um timestamp UNIX em milissegundos, seguidos por ~74 bits de aleatoriedade criptograficamente segura.
Como funciona:
0 1 2 3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
├─┤─┤─┤─┤─┤─┤─┤─┤─┤─┤─┤─┤─┤─┤─┤─┤─┤─┤─┤─┤─┤─┤─┤─┤─┤─┤─┤─┤─┤─┤─┤─┤
| unix_ts_ms (48 bits) |
├─┤─┤─┤─┤─┤─┤─┤─┤─┤─┤─┤─┤─┤─┤─┤─┤─┤─┤─┤─┤─┤─┤─┤─┤─┤─┤─┤─┤─┤─┤─┤─┤
| unix_ts_ms | ver | rand_a (12 bits) |
├─┤─┤─┤─┤─┤─┤─┤─┤─┤─┤─┤─┤─┤─┤─┤─┤─┤─┤─┤─┤─┤─┤─┤─┤─┤─┤─┤─┤─┤─┤─┤─┤
|var| rand_b (62 bits) |
├─┤─┤─┤─┤─┤─┤─┤─┤─┤─┤─┤─┤─┤─┤─┤─┤─┤─┤─┤─┤─┤─┤─┤─┤─┤─┤─┤─┤─┤─┤─┤─┤
Como UUIDs gerados no mesmo milissegundo compartilham um prefixo de timestamp, eles se agrupam nos indices B-tree. Novas insercoes sao anexadas proximo ao final da arvore em vez de se espalharem aleatoriamente — o mesmo padrao de acesso que torna inteiros auto-incrementais rapidos.
Exemplo: 019078e5-d2c7-7b3a-8f1e-4a6d5c8b2e91 — os primeiros 12 caracteres hexadecimais codificam o horario de criacao.
O Que a RFC 9562 Mudou
Antes da RFC 9562, UUIDs ordenados por tempo existiam apenas como propostas informais. A RFC, publicada em maio de 2024, tornou o UUID v7 um padrao oficial do IETF com um layout de bits definido. Ela cataloga 16 implementacoes diferentes nao padronizadas de IDs ordenados por tempo — incluindo ULID, Snowflake do Twitter e ShardId do Instagram — que motivaram sua criacao.
O impacto pratico: autores de bibliotecas agora tem uma unica especificacao para implementar, e bancos de dados estao adicionando suporte nativo. O PostgreSQL 18 (lancado no final de 2025) incluiu uma funcao nativa uuidv7(), eliminando a necessidade de extensoes ou geracao no nivel da aplicacao.
O uuidv7() Nativo do PostgreSQL 18
O PostgreSQL 18, lancado no final de 2025, adiciona duas novas funcoes:
-- Gerar um UUID v7 ordenado por tempo
SELECT uuidv7();
-- Resultado: 019078e5-d2c7-7b3a-8f1e-4a6d5c8b2e91
-- Gerar um UUID v4 aleatorio (alias para gen_random_uuid())
SELECT uuidv4();
A implementacao do PostgreSQL adiciona uma fracao de timestamp sub-milissegundo de 12 bits, proporcionando melhor ordenacao monotomica dentro de um unico processo backend. Isso significa que ate linhas inseridas no mesmo milissegundo mantem a ordem de criacao — importante para tabelas de alto throughput.
Para versoes anteriores do PostgreSQL, voce pode gerar UUID v7 no nivel da aplicacao ou usar extensoes como pg_idkit.
UUID v4 vs v7: Comparacao Direta
| Propriedade | UUID v4 | UUID v7 |
|---|---|---|
| Formato | 128 bits, 36 caracteres hex | 128 bits, 36 caracteres hex |
| Bits aleatorios | 122 | ~74 |
| Ordenavel por tempo de criacao | Nao | Sim (precisao de ms) |
| Desempenho de indice B-tree | Ruim em escala | Excelente |
| Vazamento de timestamp | Nenhum | Sim (precisao de ms) |
| Padrao RFC | RFC 4122 / RFC 9562 | RFC 9562 (maio de 2024) |
| Suporte nativo em bancos de dados | Todos os principais | PostgreSQL 18+, crescendo |
| Suporte de bibliotecas | Universal | Amplo e crescendo |
| Tamanho de armazenamento | 16 bytes (binario) | 16 bytes (binario) |
| Compatibilidade de tipo de coluna | uuid / BINARY(16) | uuid / BINARY(16) — mesma coluna, totalmente compativel |
O ponto crucial: v4 e v7 sao compativeis na mesma coluna. Eles usam o mesmo tipo de dados uuid, o mesmo armazenamento binario de 16 bytes, a mesma representacao em string de 36 caracteres. Voce pode armazenar ambos na mesma coluna, o que torna a migracao incremental simples.
Experimente voce mesmo: UUID Generator — gere identificadores UUID v4 instantaneamente no seu navegador, com geracao em lote e copia com um clique.
UUID v7 vs ULID: Voce Ainda Precisa do ULID?
O ULID (Universally Unique Lexicographically Sortable Identifier) foi lancado em 2016 para resolver o mesmo problema que o UUID v7 agora resolve: identificadores unicos globais ordenados por tempo. Veja como eles se comparam:
| Propriedade | UUID v7 | ULID |
|---|---|---|
| Codificacao | 36 caracteres hex com hifens | 26 caracteres Crockford Base32 |
| Timestamp | 48 bits ms epoch | 48 bits ms epoch |
| Bits aleatorios | ~74 | 80 |
| Padrao | IETF RFC 9562 | Especificacao comunitaria (sem RFC) |
| Ordenacao monotomica | Depende da implementacao | Incremento definido na spec dentro do mesmo ms |
| Tipo no banco de dados | Coluna nativa uuid | Requer CHAR(26) ou BINARY(16) |
| Seguro para URL | Nao (hifens) | Sim (Base32) |
| Timestamp valido ate | Ano 10889 | Ano 10889 |
Onde o UUID v7 Vence
-
Padronizacao. O UUID v7 tem uma RFC do IETF. Todo banco de dados, ORM e runtime de linguagem ja entende o tipo UUID. O ULID requer parsing customizado na maioria dos ecossistemas.
-
Suporte nativo em bancos de dados. ULIDs nao cabem na coluna nativa
uuiddo PostgreSQL sem conversao. Voce ou armazena como strings (desperdicando espaco) ou converte para binario (perdendo a codificacao Crockford). O UUID v7 encaixa diretamente em colunasuuidexistentes. -
Momentum do ecossistema. A Bytebase preve que a industria vai “gradualmente abandonar solucoes sob medida e convergir para o UUIDv7 como chave primaria na maioria dos casos de uso.” O
uuidv7()nativo do PostgreSQL 18 acelera isso.
Onde o ULID Ainda Faz Sentido
-
Representacao compacta. Com 26 caracteres contra 36, ULIDs sao mais curtos em URLs e APIs. Se o comprimento da string importa para seu caso de uso, o ULID e mais compacto.
-
Um pouco mais de aleatoriedade. O ULID fornece 80 bits aleatorios contra ~74 do UUID v7. Na pratica, ambos tem taxas de colisao astronomicamente baixas, mas o ULID tem um componente aleatorio marginalmente maior.
-
Infraestrutura ULID existente. Se seu sistema ja usa ULIDs e o custo de migracao nao e trivial, nao ha razao urgente para mudar. Ambos oferecem desempenho comparavel no banco de dados, ja que compartilham o mesmo prefixo de timestamp de 48 bits.
Para novos projetos em 2026, o UUID v7 e a escolha mais segura. Ele e padronizado, suportado nativamente por bancos de dados e nao exige que sua equipe mantenha logica de parsing de ULID.
Desempenho em Bancos de Dados: Benchmarks Reais
A diferenca de desempenho entre identificadores aleatorios e ordenados por tempo e bem documentada em sistemas de producao:
PostgreSQL
| Metrica | UUID v4 | UUID v7 / Sequencial |
|---|---|---|
| Throughput de INSERT (dataset grande) | 20-30% da base | 100% da base |
| Volume de WAL | ~20 GB | ~2,5 GB |
| Taxa de acerto de cache | 85% | 99% |
Fonte: Benchmark da EnterpriseDB. A diferenca aumenta conforme os datasets excedem a RAM disponivel.
MySQL / InnoDB
O motor InnoDB do MySQL usa indices clusterizados, onde a chave primaria determina a ordem fisica das linhas. UUIDs aleatorios sao especialmente custosos:
- A utilizacao de paginas B+ tree cai para ~50% (contra 94% sequencial)
- UUID armazenado como
CHAR(36)e 9x maior que um inteiro de 32 bits BINARY(16)e o formato de armazenamento recomendado — 4x maior que um inteiro, mas compacto o suficiente para a maioria das cargas de trabalho
Fonte: Analise da PlanetScale.
Quando Manter Auto-Increment
UUIDs nem sempre sao a resposta. Inteiros auto-incrementais continuam sendo a escolha certa quando:
- Voce opera um unico banco de dados sem planos de sharding
- O throughput de escrita importa mais que a unicidade global
- Contagens de linhas nao sao informacoes sensiveis
- Voce nao precisa gerar IDs fora do banco de dados
Para sistemas distribuidos, microsservicos ou qualquer arquitetura onde IDs devem ser gerados no nivel da aplicacao, o UUID v7 oferece tanto o desempenho de chaves sequenciais quanto a flexibilidade da geracao descentralizada.
Como Gerar UUID v7
JavaScript / TypeScript
// Using the 'uuid' package (v10+)
import { v7 as uuidv7 } from 'uuid';
const id = uuidv7(); // '019078e5-d2c7-7b3a-8f1e-4a6d5c8b2e91'
Python
# Python 3.x with uuid7 package
from uuid_extensions import uuid7
id = str(uuid7()) # '019078e5-d2c7-7b3a-8f1e-4a6d5c8b2e91'
Go
// Using github.com/gofrs/uuid/v5
import "github.com/gofrs/uuid/v5"
id, _ := uuid.NewV7()
fmt.Println(id.String()) // "019078e5-d2c7-7b3a-8f1e-4a6d5c8b2e91"
PostgreSQL 18+
-- Native function, no extension needed
CREATE TABLE orders (
id uuid PRIMARY KEY DEFAULT uuidv7(),
customer_id uuid NOT NULL,
created_at timestamptz DEFAULT now()
);
Outras Linguagens
Bibliotecas de UUID v7 estao disponiveis para Rust (crate uuid v1.4+), Java (uuid-creator), C# (UUIDNext) e PHP (symfony/uid).
Migrando de UUID v4 para v7
Ja usa UUID v4 em producao? A boa noticia: a migracao nao exige uma troca total de uma vez.
v4 e v7 Podem Coexistir
Ambas as versoes compartilham o mesmo tipo de coluna uuid e a representacao binaria de 16 bytes. Voce pode comecar a gerar v7 para novas linhas enquanto as linhas v4 existentes permanecem intactas. Consultas, joins e indices funcionam de forma identica — o banco de dados nao se importa com qual versao um UUID e.
A unica diferenca comportamental: novas linhas v7 serao ordenadas apos as linhas v4 mais antigas quando ordenadas pela chave primaria, ja que o prefixo de timestamp do v7 as coloca mais adiante na ordem lexicografica. Se sua aplicacao depende da ordenacao de UUIDs (o que nao deveria acontecer com v4), verifique essa premissa.
Checklist de Migracao
- Atualize sua geracao de IDs — mude a geracao de UUID no nivel da aplicacao para v7. Para PostgreSQL 18+, altere o valor padrao da coluna para
uuidv7(). - Atualize os ORMs — a maioria dos ORMs delega a geracao de UUID para a aplicacao ou o banco de dados. Atualize o gerador, nao o tipo da coluna.
- Monitore o desempenho dos indices — apos a mudanca, novas insercoes serao sequenciais. Com o tempo, seus indices se tornarao naturalmente mais eficientes conforme as linhas v7 predominam.
- Nao faca backfill — converter valores v4 existentes para v7 e desnecessario e quebraria referencias de chave estrangeira. Deixe v4 e v7 coexistirem.
Consideracao de Privacidade: Timestamps nos Seus IDs
O UUID v7 codifica o horario de criacao com precisao de milissegundos. Qualquer pessoa que possa ver o UUID pode extrair quando ele foi criado. Para chaves internas de banco de dados, isso raramente e uma preocupacao. Mas considere as implicacoes para:
- APIs publicas — se sua API expoe IDs de entidades, os clientes podem determinar quando os recursos foram criados. Isso pode revelar padroes de negocio (volume de pedidos, taxa de crescimento de usuarios).
- Tokens de sessao e chaves de API — prefira UUID v4 para segredos. O timestamp no v7 nao agrega valor para tokens e revela informacoes de tempo desnecessariamente.
- Conformidade regulatoria — dependendo da sua jurisdicao, timestamps de criacao embutidos em identificadores podem constituir dados pessoais se puderem ser vinculados a um usuario.
Uma abordagem pratica: use UUID v7 para chaves primarias de banco de dados (internas), UUID v4 para tokens e chaves de API visiveis externamente.
Experimente voce mesmo: UUID Generator — precisa de um lote de UUIDs para testes? Gere ate 25 de uma vez, copie individualmente ou baixe como arquivo de texto.
Perguntas Frequentes
Dois UUIDs podem ser iguais?
Teoricamente sim, mas na pratica nao. Os 122 bits aleatorios do UUID v4 dao um espaco de chaves de 5,3 x 10^36. Voce precisaria gerar um bilhao de UUIDs por segundo durante 86 anos para atingir uma probabilidade de colisao de 50%. O UUID v7 tem menos bits aleatorios (~74), mas colisoes dentro do mesmo milissegundo ainda sao astronomicamente improvaveis.
Devo armazenar UUIDs como strings ou binario?
Binario. Um UUID armazenado como CHAR(36) usa 36 bytes; como BINARY(16) usa 16 bytes — menos da metade do armazenamento. O tipo nativo uuid do PostgreSQL armazena como binario de 16 bytes automaticamente. No MySQL, use BINARY(16) e converta no nivel da aplicacao. A PlanetScale observa que CHAR(36) e 9x maior que um inteiro de 32 bits, tornando o armazenamento binario essencial para tabelas grandes.
Como o UUID v7 se compara ao Twitter Snowflake?
Ambos sao identificadores distribuidos ordenados por tempo, mas servem a necessidades diferentes. IDs Snowflake sao de 64 bits (menores, mais rapidos para comparar), mas requerem um servico de coordenacao central para atribuir IDs de worker. O UUID v7 e de 128 bits e nao requer coordenacao — qualquer no pode gerar um independentemente. A RFC 9562 lista explicitamente o Snowflake entre as 16 implementacoes nao padronizadas que motivaram a criacao do UUID v7.
Como gerar UUID v7 no PostgreSQL antes da versao 18?
Antes do suporte nativo, voce tem varias opcoes: a extensao pg_idkit, geracao no nivel da aplicacao (gere no codigo da sua aplicacao e passe para o banco de dados) ou uma funcao PL/pgSQL que monta o timestamp e os bytes aleatorios manualmente. Atualizar para o PostgreSQL 18 e o caminho mais limpo se sua infraestrutura permitir.
O UUID v7 e seguro para chaves de API?
Nao — use UUID v4 para segredos. O timestamp do UUID v7 revela quando a chave foi criada, o que e uma informacao desnecessaria em um contexto de seguranca. Para chaves de API e tokens de sessao, voce quer entropia maxima sem metadados embutidos. Os 122 bits de pura aleatoriedade de um CSPRNG do UUID v4 sao apropriados, embora formatos de token dedicados possam oferecer recursos adicionais como expiracao integrada.
Qual Voce Deve Escolher? Um Framework de Decisao
Escolha UUID v4 quando:
- Voce precisa de aleatoriedade maxima (tokens, chaves de API, IDs de sessao)
- O horario de criacao deve permanecer privado
- Voce esta adicionando UUIDs a uma tabela pequena com poucas escritas, onde a fragmentacao de indices nao importa
Escolha UUID v7 quando:
- O UUID serve como chave primaria do banco de dados
- Voce precisa de ordenacao temporal sem uma coluna
created_atextra - O throughput de escrita importa em escala
- Voce quer os beneficios de chaves sequenciais sem uma autoridade central
Escolha ULID quando:
- Voce precisa de uma representacao em string mais curta (26 caracteres contra 36)
- Seu sistema ja roda com infraestrutura ULID
- Voce precisa de identificadores seguros para URL sem codificacao
Para a maioria dos novos projetos em 2026, UUID v7 e a recomendacao padrao. Ele combina a geracao descentralizada do UUID v4 com o desempenho de banco de dados de chaves sequenciais, respaldado por um padrao IETF e suporte nativo crescente em bancos de dados. A convergencia em direcao ao v7 esta em andamento — a funcao nativa uuidv7() do PostgreSQL 18 e o sinal mais claro ate agora.
Independentemente da sua escolha, voce pode gerar identificadores UUID v4 instantaneamente com o UUID Generator — ou formatar suas respostas de API contendo UUIDs com o JSON Formatter.