O que é UUID e quais versões existem
UUID é um identificador único de 128 bits. Entenda por que ele substitui o auto-increment e qual versão usar — com destaque para o v7 em tabelas de alta escrita.
Você precisa criar o registro antes de conhecer o seu identificador. Esse é o problema de fundo. Com auto-increment, o banco só te entrega o ID depois do INSERT — então você não pode gerar a chave no cliente, não pode montar relações antes do commit, e não pode coordenar dois serviços que escrevem na mesma tabela sem um ponto central de sincronização. O UUID resolve isso invertendo a ordem: o identificador nasce antes do registro, em qualquer máquina, sem perguntar nada ao banco.
Este artigo explica o que é um UUID, por que ele substitui (ou não) o auto-increment, e quais das versões realmente importam na prática — com uma opinião firme sobre qual usar quando a tabela escreve muito.
O que é um UUID, em concreto
UUID é um identificador único de 128 bits. Na forma textual canônica ele aparece como 32 dígitos hexadecimais em cinco grupos separados por hífen, no formato 8-4-4-4-12. O número total de valores possíveis é grande o bastante para que a colisão entre dois UUIDs gerados de forma independente seja, na prática, desprezível — você não precisa de um servidor central distribuindo faixas para garantir unicidade.
É justamente essa unicidade sem coordenação que dá ao UUID as suas três vantagens reais sobre o auto-increment. Primeiro: ele é gerável no cliente. O frontend, um worker ou um microsserviço criam o ID antes de tocar no banco. Segundo: não há ponto central de contenção — dois bancos em regiões diferentes podem gerar chaves para a mesma tabela lógica sem se falar. Terceiro: o UUID não vaza a contagem de registros. Um ID sequencial 47 na URL conta para qualquer um quantas linhas existem e abre a porta para enumeração; um UUID não diz nada sobre quantos vizinhos ele tem.
As versões que importam
A especificação define várias versões de UUID, mas no dia a dia você vai lidar com três, e talvez ouvir falar de mais duas. A versão é codificada dentro do próprio valor, então dá para saber qual gerou cada ID só de olhar.
A v4 é o padrão de fato. Ela é quase inteiramente aleatória: 122 bits de entropia, alguns bits fixos para marcar versão e variante. Não carrega timestamp, não carrega informação de máquina, não diz nada sobre quando ou onde foi gerada. É o que a maioria das bibliotecas entrega por padrão quando você pede "um UUID".
3f9a1c2e-7b4d-4f8a-9c1e-2a6b8d0f3e57
A v1 combina timestamp com o endereço MAC da placa de rede da máquina que gerou o ID. Em troca de ser ordenável no tempo, ela vaza duas coisas que você raramente quer expor: o instante exato da criação e um identificador de hardware. Hoje quase não há motivo para escolher v1 — a v7 entrega o lado bom sem o lado ruim.
A v7 é a versão que mudou o jogo. Ela coloca um timestamp em milissegundos nos bits mais significativos e preenche o resto com aleatoriedade. O resultado é um ID que é único como o v4, mas ordenável no tempo: dois UUIDs v7 gerados em sequência ordenam, como string ou como bytes, na ordem em que foram criados.
0190d4f2-3c7a-7e10-8b6f-1d2c3a4b5e6f
Repare no 7 que abre o terceiro grupo — é o nibble de versão. No v4 acima, esse mesmo dígito era 4.
Por fim, v3 e v5 são determinísticas: você passa um namespace e um nome, e elas devolvem sempre o mesmo UUID via hash (MD5 na v3, SHA-1 na v5). Servem quando você quer um ID estável derivado de uma entrada conhecida — por exemplo, mapear uma URL ou um e-mail para um identificador reproduzível. Não são para chave primária de linha nova; são para dedupe e idempotência.
O custo de usar UUID como primary key
Nada disso é de graça. Um auto-increment cabe em 4 bytes (INT) ou 8 bytes (BIGINT). Um UUID ocupa 16 bytes. Isso parece pouco até você lembrar que a primary key é replicada em toda secondary index da tabela, e em toda foreign key que aponta para ela. Em uma tabela com vários índices, a diferença de 8 a 12 bytes por linha se multiplica e infla o tamanho em disco e em memória — menos linhas por página, mais I/O, cache menos eficiente.
Guardar o UUID como texto de 36 caracteres piora tudo. Use o tipo nativo do banco (uuid no Postgres) ou BINARY(16) quando não houver um; nunca VARCHAR(36) para a chave.
v4 versus v7 em tabela de alta escrita
Aqui vem a opinião, e ela é firme: para tabela de alta escrita, use v7, não v4.
O motivo é o índice. A primary key normalmente é um índice B-tree clusterizado ou clustered-friendly. Quando os IDs chegam em ordem aproximadamente crescente, cada novo INSERT cai na última página do índice — localidade boa, poucas páginas sujas, pouca reorganização. É exatamente o comportamento que o auto-increment sempre teve de graça.
O v4 destrói isso. Como ele é aleatório, cada INSERT cai numa posição arbitrária do índice. Você suja páginas espalhadas por toda a estrutura, força page splits no meio da árvore e fragmenta o índice. Em volume alto de escrita isso vira write amplification e queda de throughput visível.
O v7 recupera a localidade temporal: como o prefixo é um timestamp, inserts próximos no tempo caem próximos no índice, igual ao auto-increment — só que sem coordenação central e gerável no cliente. Você fica com o melhor dos dois mundos. Se a sua stack ainda não gera v7 nativamente, dá para gerar um UUID v7 direto no navegador para testar o formato antes de fechar o esquema.
A escolha de tipo de chave também conversa com a escolha de banco — vale o mesmo cuidado que você tem ao decidir entre Postgres e MySQL, porque o suporte nativo a uuid e o comportamento de índice clusterizado diferem entre os dois.
Quando o auto-increment ainda basta
Não troque por reflexo. Se a tabela é interna, de baixa escrita, vive num único banco e nunca expõe o ID numa URL pública, um BIGINT auto-increment é menor, mais rápido e mais simples de ler em log. UUID paga por flexibilidade — geração distribuída, sem vazamento de contagem, sem coordenação. Se você não usa nenhuma dessas três coisas, está só pagando 16 bytes e um índice maior por nada.
Perguntas frequentes
UUID v4 pode colidir?
Em teoria sim, na prática não. São 122 bits de aleatoriedade, o que dá um espaço de valores grande o suficiente para que a chance de duas máquinas gerarem o mesmo v4 seja desprezível dentro de qualquer volume realista. O risco real não é a matemática — é um gerador de aleatoriedade mal configurado. Use a biblioteca padrão da plataforma e confie nela.
Devo guardar UUID como texto ou binário?
Binário, sempre que possível. No Postgres use o tipo uuid nativo, que armazena os 128 bits em 16 bytes. Onde não houver tipo nativo, use BINARY(16). Guardar como VARCHAR(36) mais que dobra o espaço da chave e desperdiça memória em todo índice que a referencia.
v7 já é seguro para produção?
Sim. A versão foi padronizada e as bibliotecas das principais linguagens já a implementam. Se a sua versão de biblioteca ou de banco ainda não gera v7 nativamente, atualize ou gere o valor na camada de aplicação — o formato em si é estável e não vai mudar.
Posso migrar de auto-increment para UUID depois?
Pode, mas não é trivial. Você precisa adicionar a coluna UUID, popular as linhas existentes, reapontar todas as foreign keys e só então trocar a primary key. Em tabela grande isso é uma migração planejada com downtime ou com escrita dupla — não um ALTER TABLE de cinco minutos. Decidir cedo é mais barato.
O que levar daqui
UUID resolve um problema concreto: gerar identificadores únicos sem coordenação central, no cliente, sem vazar contagem. Se você não precisa de nenhuma dessas três propriedades, o auto-increment continua menor e mais rápido. Se precisa, escolha a versão pelo uso: v4 para a maioria dos casos, v3/v5 quando o ID tem que ser determinístico, e v7 — não v4 — sempre que a tabela escreve muito, porque a localidade temporal do v7 é o que mantém o seu índice B-tree saudável sob carga.
- 01 Salt, pepper, bcrypt e Argon2id: como proteger senhas de verdade Em 2012, o LinkedIn expôs 117mi de senhas. SHA-1 sem salt — 90% quebradas em 4h. Entenda o que cada camada de proteção resolve e por que Argon2id é a escolha certa hoje.
- 02 Licenças MIT, Apache e GPL: diferenças práticas para devs MIT, Apache 2.0 e GPL não são a mesma coisa. Entenda permissiva vs copyleft, proteção de patentes e compatibilidade antes de colocar código em produção.