Probabilidade de colisão usando bits mais significativos de um UUID em Java

235

Se estou usando Long uuid = UUID.randomUUID().getMostSignificantBits()a probabilidade de uma colisão. Ele corta os bits menos significativos, então existe a possibilidade de você colidir, certo?

dlinsin
fonte

Respostas:

213

De acordo com a documentação , o método estático UUID.randomUUID()gera um UUID do tipo 4.

Isso significa que seis bits são usados ​​para algumas informações de tipo e os 122 bits restantes são atribuídos aleatoriamente.

Os seis bits não aleatórios são distribuídos com quatro na metade mais significativa do UUID e dois na metade menos significativa. Portanto, a metade mais significativa do seu UUID contém 60 bits de aleatoriedade, o que significa que, em média, você precisa gerar 2 ^ 30 UUIDs para obter uma colisão (em comparação com 2 ^ 61 para o UUID completo).

Então, eu diria que você está bem seguro. Observe, no entanto, que isso não é absolutamente verdade para outros tipos de UUIDs, como Carl Seleborg menciona.

Aliás, você seria um pouco melhor usando a metade menos significativa do UUID (ou apenas gerando um tempo aleatório usando o SecureRandom).

Rasmus Faber
fonte
3
Não tenho certeza se isso está totalmente correto - olhando para a implementação, é claro que as informações de versão / variante não são armazenadas nos bits mais significativos, mas em algum lugar no meio.
Tom
2
@RasmusFaber O comentário de Tom está correto: A resposta aqui está incorreta sobre os seis bits mais significativos que estão sendo informações de tipo. Na verdade, existem seis bits de dados não aleatórios, mas quatro bits identificam a versão 4 e outros dois bits são reservados. Os quatro e dois bits estão localizados em posições diferentes, próximo ao meio do valor de 128 bits. Veja o artigo da Wikipedia .
Basil Bourque
10

É melhor gerar apenas um valor longo aleatório, e todos os bits são aleatórios. No Java 6, o novo Random () usa o System.nanoTime () mais um contador como semente.

Existem diferentes níveis de exclusividade.

Se você precisar de exclusividade em muitas máquinas, poderá ter uma tabela de banco de dados central para alocar IDs exclusivos ou até lotes de IDs exclusivos.

Se você só precisa ter exclusividade em um aplicativo, pode simplesmente ter um contador (ou um contador que comece no currentTimeMillis () * 1000 ou nanoTime (), dependendo de seus requisitos)

Peter Lawrey
fonte
7

Use Hora YYYYDDDD(Ano + Dia do Ano) como prefixo. Isso diminui a fragmentação do banco de dados em tabelas e índices. Este método retorna byte[40]. Usei-o em um ambiente híbrido onde o SID do Active Directory ( varbinary(85)) é a chave para usuários LDAP e um ID gerado automaticamente pelo aplicativo é usado para usuários não LDAP. Além disso, o grande número de transações por dia em tabelas transacionais (setor bancário) não pode usar Inttipos padrão para chaves

private static final DecimalFormat timeFormat4 = new DecimalFormat("0000;0000");

public static byte[] getSidWithCalendar() {
    Calendar cal = Calendar.getInstance();
    String val = String.valueOf(cal.get(Calendar.YEAR));
    val += timeFormat4.format(cal.get(Calendar.DAY_OF_YEAR));
    val += UUID.randomUUID().toString().replaceAll("-", "");
    return val.getBytes();
}
Dr Bob
fonte
3
Por que não usar um UUID V1 padrão?
ShadowChaser