UUID v4, fragmentação de índice e por que UUID v7 melhora isso | UUID | CSharp
- UUID v4, fragmentação de índice e por que UUID v7 melhora isso | UUID | CSharp
Uma crítica comum ao uso de UUID v4 como chave primária em bancos relacionais é o impacto que ele pode causar na estrutura física dos índices, especialmente em índices baseados em B-Tree.
O problema do UUID v4 em índices
O UUID v4 é essencialmente aleatório. Isso significa que, a cada novo registro inserido, o valor da chave primária pode cair em qualquer ponto lógico do índice.
Em bancos como PostgreSQL, MySQL/InnoDB e SQL Server, isso tende a gerar efeitos como:
- menor localidade de escrita
- páginas do índice sendo acessadas de forma mais dispersa
- maior chance de page split
- pior aproveitamento de cache
- aumento de operações de I/O aleatório
Na prática, o banco não sofre porque o UUID é “grande” apenas. O problema principal é que a chave chega em ordem aleatória, o que dificulta inserções mais contíguas no índice.
Por que B-Trees preferem chaves ordenáveis
Estruturas de índice do tipo B-Tree funcionam melhor quando novos valores entram em ordem crescente ou aproximadamente crescente.
Exemplo de chave sequencial:
1001
1002
1003
1004
Nesse cenário, novas inserções tendem a ocorrer próximas do “fim” lógico do índice, reduzindo reorganizações internas.
Agora compare com chaves aleatórias:
8f2a...
13bc...
ff09...
4471...
Nesse caso, cada novo valor pode precisar ser inserido em posições muito diferentes da árvore, espalhando escrita e aumentando o custo de manutenção estrutural do índice.
O que isso pode causar na prática
Dependendo do volume e do padrão de escrita, usar UUID v4 pode levar a:
- aumento de fragmentação
- crescimento do índice acima do necessário
- pior desempenho de inserção
- pior desempenho de leitura indexada em alguns cenários
- mais pressão em memória e disco
Esse efeito costuma ser mais perceptível quando:
- a tabela é muito grande
- há alta taxa de
INSERT - a chave primária também é usada como índice clustered ou influencia fortemente a organização física dos dados
- existem muitos índices secundários dependentes da PK
Onde entra o UUID v7
O UUID v7 foi projetado para manter a unicidade global, mas com uma característica importante: seus bits mais significativos carregam informação temporal.
De forma simplificada:
[ timestamp ][ versão ][ variante ][ aleatoriedade ]
Isso faz com que GUIDs gerados em momentos próximos tenham valores também próximos em ordem lexical/binária.
Resultado prático:
- inserções mais previsíveis no índice
- menor dispersão de escrita
- melhor localidade
- menos fragmentação do que UUID v4
- comportamento mais amigável para B-Tree
UUID v7 é igual a um inteiro sequencial?
Não.
Ele não se comporta exatamente como um BIGINT IDENTITY, BIGSERIAL ou sequência monotônica pura.
Diferenças importantes:
- continua tendo 128 bits
- ainda possui parte aleatória
- a ordenação é temporal, não necessariamente estritamente sequencial em todos os cenários
- em sistemas distribuídos, clocks e concorrência podem introduzir pequenas variações
Mesmo assim, para o banco, o UUID v7 tende a ser muito melhor do que o UUID v4 quando o objetivo é reduzir fragmentação e melhorar a localidade de escrita.
Quando UUID v4 ainda pode ser aceitável
UUID v4 não é “errado”. Ele continua sendo uma opção válida quando:
- a simplicidade importa mais do que a performance de índice
- o volume de escrita não é alto
- a tabela não é grande o suficiente para esse custo aparecer de forma relevante
- a chave primária não é o principal gargalo da aplicação
- o sistema já está consolidado e a troca não compensa
Ou seja: o problema não é “UUID v4 é proibido”. O problema é usar UUID v4 sem considerar o efeito físico que isso gera no banco.
Quando UUID v7 tende a ser a melhor escolha
UUID v7 costuma ser uma escolha melhor quando você quer:
- IDs globais únicos
- geração distribuída
- melhor ordenação temporal
- menor fragmentação de índice
- melhor comportamento em banco do que UUID v4
Ele é especialmente interessante para:
- sistemas de alta taxa de escrita
- tabelas grandes
- workloads intensivos em inserção
- cenários em que a PK participa fortemente dos índices
Resumo prático
| Tipo | Unicidade global | Ordenação temporal | Impacto em índice |
|---|---|---|---|
| UUID v4 | Sim | Não | Pior localidade, mais fragmentação |
| UUID v7 | Sim | Sim | Melhor localidade, menor fragmentação |
| BIGINT sequencial | Não distribuído por natureza | Sim | Melhor comportamento para B-Tree |
Conclusão técnica desta comparação
O comentário está certo ao afirmar que UUID v4 pode prejudicar o banco em comparação com identificadores ordenáveis. O ganho do UUID v7 está justamente em reduzir esse custo sem abrir mão da unicidade distribuída.
A forma mais precisa de dizer isso é:
UUID v4 resolve muito bem o problema de geração distribuída de IDs, mas pode degradar a eficiência dos índices devido à aleatoriedade. UUID v7 preserva a unicidade global e adiciona ordenação temporal, tornando-se mais adequado para bancos que usam B-Tree.