UUID v4 vs v7: Qual você deve usar?
UUID v4 vs v7 para chaves primárias de banco de dados: por que v7 melhora inserções, quando v4 preserva a privacidade e como gerar ambos.
Para uma nova chave primária de banco de dados em 2026, adote UUID v7 como padrão e recorra ao v4 apenas quando o identificador for público e o momento de sua criação precisar permanecer privado.
Se você já observou a latência de inserção aumentar gradualmente em uma tabela movimentada e rastreou a causa até uma chave primária que cai em um canto diferente do índice a cada vez, esta questão vai lhe parecer familiar. A solução acaba sendo bem menor do que uma migração de schema. Ambos os formatos são UUIDs de 128 bits padronizados na mesma RFC, portanto a escolha não é sobre compatibilidade ou segurança contra colisões. Tudo se resume a uma propriedade: se os seus IDs são ordenáveis pela ordem de criação. A ordenação temporal do v7 corrige a fragmentação de índice que chaves v4 aleatórias causam em tabelas com escrita intensa, ao custo de embutir um timestamp legível em cada valor. Este guia detalha a diferença estrutural, o mecanismo de índice de banco de dados por trás do desempenho de escrita do v7, o trade-off de privacidade, o suporte atual das bibliotecas e um padrão decisivo.
Principais Conclusões
- UUID v4 e v7 são ambos identificadores de 128 bits e 16 bytes padronizados na RFC 9562 (maio de 2024); o v7 substitui os 48 bits iniciais por um timestamp Unix em milissegundos, de modo que seus valores são ordenáveis pela ordem de criação, enquanto o v4 é totalmente aleatório.
- Chaves v4 aleatórias se dispersam por um índice B-tree e causam divisões de página (page splits), rotatividade de cache e fragmentação; o prefixo ordenado temporalmente do v7 faz com que as inserções ocorram próximas ao fim do índice, comportando-se de forma muito mais parecida com uma chave sequencial.
- Um ID v7 revela seu próprio momento de criação com precisão de milissegundos; um ID v4 não. Use v4 para identificadores públicos, links de convite ou qualquer lugar onde sua taxa de crescimento deva permanecer privada.
- O suporte ao v7 é de primeira classe: o PostgreSQL 18 traz o
uuidv7()nativo, o Python 3.14 adicionouuuid.uuid7(), e o pacote JavaScriptuuid(v14.x) exportav7(). - Nenhum UUID é um segredo: use um token aleatório dedicado de 256 bits para autenticação e reserve os UUIDs para identidade.
Qual é a diferença entre UUID v4 e v7?
UUID v4 e v7 são ambos identificadores de 128 bits e 16 bytes padronizados na RFC 9562, publicada em maio de 2024 como um documento Standards-Track que torna obsoleta a antiga RFC 4122. A única diferença estrutural está na origem dos bits. O UUID v4 tem 122 bits de aleatoriedade com 6 bits reservados para marcadores de versão e variante, o que o torna totalmente aleatório e não ordenado. O UUID v7 substitui os 48 bits iniciais por um timestamp Unix em milissegundos e preenche os ~74 bits restantes com aleatoriedade (mais os marcadores de versão e variante), de forma que os valores v7 são ordenáveis pela ordem de criação, tanto lexicograficamente quanto byte a byte, enquanto os valores v4 não são.
UUID v4: [ 122 random bits ...................... ] + version/variant
UUID v7: [ 48-bit ms timestamp ][ ~74 random bits ] + version/variant
Essa única mudança é toda a decisão. Ambos mantêm a mesma matemática de colisão proveniente da porção aleatória, ambos cabem na mesma coluna e ambos são cobertos pelo mesmo padrão.
Discover how at OpenReplay.com.
Por que o UUID v7 vence como chave de banco de dados?
O v7 supera o v4 como chave primária porque seu prefixo de timestamp dá às inserções uma localidade de índice que chaves aleatórias destroem. Chaves v4 aleatórias caem em posições aleatórias em um índice B-tree, causando divisões de página, rotatividade de cache e fragmentação, já que cada inserção atinge uma parte diferente da árvore. Esse é exatamente o problema que a RFC 9562 aponta como razão para definir o v7: quando identificadores não carregam ordenação temporal, cada nova linha precisa ser escrita onde quer que seu valor aleatório caia, enquanto valores gerados um após o outro sob um esquema ordenado temporalmente acabam como vizinhos no índice. O prefixo monotônico do v7 significa que novas linhas são anexadas próximo ao fim do índice, então as divisões de página tornam-se raras e a taxa de inserção se aproxima da de uma chave inteira sequencial, mantendo a segurança contra colisões e a geração distribuída dos UUIDs.
A penalidade é pior em engines com índice clusterizado. No MySQL InnoDB e no SQL Server, a tabela é fisicamente ordenada pela chave primária, então inserções aleatórias reescrevem páginas por toda a estrutura. O PostgreSQL armazena linhas em uma heap com índices separados, o que é menos sensível à aleatoriedade da chave, mas seus índices ainda perdem localidade de cache com chaves v4 aleatórias. A magnitude varia conforme a engine, a carga de trabalho e o hardware, portanto trate percentuais específicos de benchmarks de blogs sem fonte com ceticismo e meça sua própria tabela. O mecanismo em si não está em disputa.
A ordenação temporal também se mantém sob inserções em rajada. As implementações adicionam um contador de submilissegundo para que IDs gerados no mesmo milissegundo continuem sendo ordenados corretamente: o uuid.uuid7() do Python reserva 42 bits como contador para que valores gerados dentro de um único milissegundo mantenham sua ordem, e o uuidv7() do PostgreSQL 18 constrói cada valor a partir de um timestamp Unix em milissegundos, uma fração de submilissegundo e bits aleatórios.
Quando o UUID v4 ainda é a escolha certa
Escolha v4 quando o ID for exposto e seu momento de criação for sensível, porque um ID v7 embute seu próprio momento de criação com precisão de milissegundos. Qualquer pessoa que consiga ler o ID consegue ler quando o registro foi criado, o que torna o v7 inadequado para identificadores voltados ao público. A equipe da Aiven chega à mesma conclusão: assim que uma chave primária é entregue a usuários finais por meio de um aplicativo externo ou API, o v7 deixa de ser uma escolha sensata, porque o identificador revela quando o registro foi criado. Use v4 para tokens de convite, links de compartilhamento ou qualquer lugar onde um concorrente possa inferir sua taxa de crescimento a partir de faixas de IDs.
Uma ressalva se aplica a ambas as versões: nenhum UUID é um token de segurança. Os bits não aleatórios no v7 são previsíveis, e a qualidade da aleatoriedade do v4 depende da implementação, portanto nenhum dos dois deve controlar a autenticação. Gere uma string criptograficamente aleatória dedicada, de pelo menos 256 bits, para segredos, e use UUIDs apenas para identidade.
Gerando v7 hoje e migrando incrementalmente
O suporte ao v7 já é amplo entre bancos de dados e linguagens, embora a versão exata importe:
| Plataforma | Geração de v7 | Versão |
|---|---|---|
| PostgreSQL | uuidv7() (nativo) | PostgreSQL 18 |
| Python | uuid.uuid7() (stdlib) | Python 3.14 |
| JavaScript / Node | v7() do uuid | uuid v14.x |
O PostgreSQL 18 lançou o uuidv7() como função nativa e adicionou um alias uuidv4() para o já existente gen_random_uuid(); no PostgreSQL 17 e anteriores você precisa de uma extensão ou de uma biblioteca do lado da aplicação. O Python adicionou uuid.uuid7() à biblioteca padrão na versão 3.14, não na 3.12, onde a chamada gera AttributeError. Em JavaScript, o pacote uuid expõe o v7 por meio de um named import ESM e, conforme seu changelog, o pacote removeu o suporte a CommonJS na v12:
// Node.js, uuid v14.x
import { v7 as uuidv7 } from "uuid";
const id = uuidv7();
-- PostgreSQL 18
SELECT uuidv7();
Se você quiser ver a diferença antes de se comprometer com um tipo de coluna, gere um lote de cada um e coloque-os lado a lado. O gerador de UUID da OpenReplay produz valores v4 ou v7 no navegador, até 500 por vez, com opções para maiúsculas, sem hífens e saída entre aspas, para que você possa colá-los diretamente em SQL ou em um fixture JSON. Ordene uma coluna de valores v7 e eles sairão na ordem de criação; faça o mesmo com v4 e eles se dispersam. Os valores vêm da Web Crypto API na sua própria aba, então nenhum deles é enviado para lugar algum.
A migração não exige reescrita. v4 e v7 compartilham o mesmo tipo de coluna uuid de 16 bytes, então você pode manter as linhas v4 existentes e gerar novas linhas como v7 na mesma tabela. A versão é codificada no próprio valor, e nenhum backfill é necessário. Novas inserções se agrupam no fim do índice, e a fragmentação diminui gradualmente à medida que as páginas são reescritas com o tempo; esse é um efeito progressivo, não uma desfragmentação instantânea.
O veredito: qual você deve usar?
Adote o UUID v7 como padrão para novas chaves primárias de banco de dados, logs e streams de eventos; escolha v4 quando a imprevisibilidade importar. O v7 oferece o desempenho de escrita de uma chave sequencial com a segurança contra colisões e a geração distribuída de um UUID, e agora tem suporte nativo nas plataformas que a maioria das equipes já utiliza. Reserve o v4 para identificadores que são públicos e onde o momento de criação deve permanecer privado.
Duas alternativas complementam a decisão. O ULID codifica a mesma ideia de timestamp mais aleatoriedade em base32 de Crockford, resultando em uma string mais curta de 26 caracteres e amigável para URLs, mas não é um padrão IETF e não conta com um tipo de coluna uuid nativo. O simples bigint com auto-incremento continua sendo a opção menor e mais rápida para um sistema pequeno, de nó único, que nunca precisará de geração distribuída de IDs.
Se você está criando uma nova tabela hoje e sentindo a dor de índice causada por chaves v4, mude as novas inserções para v7, deixe as linhas antigas onde estão e permita que o índice se estabilize. O ganho está disponível com quase nenhum custo de migração.
Perguntas Frequentes
É possível extrair o timestamp de criação de um valor UUID v7?
Sim. Como o UUID v7 armazena um timestamp Unix em milissegundos de 48 bits em seus bits iniciais, é possível decodificar quando o valor foi gerado. O PostgreSQL 18 expõe uuid_extract_timestamp() exatamente para isso, e a função foi estendida para suportar valores da versão 7. Isso é um recurso útil para depuração e consultas por intervalo de tempo, mas também é a razão pela qual o v7 revela o momento de criação e não deve ser usado para identificadores públicos quando esse tempo for sensível.
UUID v7 e v4 têm o mesmo risco de colisão?
Não, mas a diferença é insignificante na prática. O UUID v4 carrega 122 bits aleatórios, enquanto o v7 mantém aproximadamente 74 bits aleatórios após reservar 48 bits para o timestamp mais os marcadores de versão e variante. O v7 tem menos bits aleatórios, mas colisões só são possíveis entre IDs gerados no mesmo milissegundo, e as implementações adicionam um contador monotônico dentro dessa janela. Para cargas de trabalho reais, ambos são efetivamente livres de colisão em qualquer taxa de geração realista.
O UUID v7 melhora o desempenho de consultas de leitura ou apenas as inserções?
O v7 ajuda principalmente o desempenho do lado da escrita e as varreduras por intervalo, ordenando as linhas próximas umas das outras no índice, o que reduz divisões de página e melhora a localidade de cache. Não atribua grandes ganhos de leitura ao v7 sozinho. A melhoria oficial de leitura de 'até 3x' do PostgreSQL 18 vem de seu novo subsistema de I/O assíncrono, um recurso independente do uuidv7(). O escopo correto do benefício de desempenho do v7 é a localidade de índice e a taxa de inserção.
Devo migrar chaves primárias UUID v4 existentes para v7?
Normalmente não é necessária uma migração completa. v4 e v7 compartilham o mesmo tipo de coluna uuid de 16 bytes e a versão é codificada no próprio valor, então você pode deixar as linhas v4 existentes intactas e gerar novas linhas como v7 na mesma tabela, sem backfill. Novas inserções se agrupam no fim do índice e a fragmentação diminui gradualmente conforme as páginas são reescritas. Reescrever linhas antigas só vale a pena se a fragmentação já estiver causando um problema mensurável.