ID vs UUID vs PublicKey
Olá! Escrevo esse post pra compartilhar um pouco do que descobri comparando essas 3 abordagens. Na realidade, já andiantando, não descobri foi é nada(rsrs), mas não sai daí não que no final tem plot twist.
Do que estamos falando mesmo?
A ideia desse estudo foi comparar o desempenho de leitura e escrita quando o banco possui apenas IDs sequenciais, apenas UUIDs ou IDs sequenciais + um ‘ID’ para servir como chave pública. O que mais me motivou foi principalmente essa última abordagem. Agora, vamos entender mais sobre essas opções.
ID Serial
O ID Serial é uma abordagem simples e frequentemente usada para a geração de identificadores únicos em bancos de dados relacionais. Esses IDs são geralmente implementados como números inteiros autoincrementais, onde cada vez que um novo registro é criado, o valor do ID Serial é automaticamente incrementado. Alguns dos principais aspectos do uso de ID Serial incluem:
- **Simplicidade**: É fácil de implementar e usar, uma vez que a maioria dos sistemas de gerenciamento de bancos de dados oferece suporte nativo para colunas de ID Serial.
- **Eficiência**: Os IDs Serial são geralmente compactos em termos de armazenamento e podem ser usados como índices eficientes em consultas de banco de dados.
No entanto, a principal desvantagem do uso de IDs Serial é que eles não são necessariamente únicos em todo o sistema, o que pode levar a colisões de identificadores se os dados forem distribuídos em vários servidores ou sistemas.
Muito comum, talvez até pela facilidade, expormos o ID sequencial de forma direta em uma API, porém, essa abordagem apresenta um problema de segurança significativo, pois isso pode permitir que um atacante obtenha informações sensíveis e até mesmo execute ataques direcionados. Para mitigar esses problemas de segurança, é recomendável não expor IDs sequenciais diretamente em sua API. Em vez disso, você pode usar técnicas como a geração de identificadores aleatórios únicos (como UUIDs)
UUID (Identificador Único Universal)
Os UUIDs são identificadores únicos gerados de forma aleatória ou baseados em informações específicas, como um timestamp e o endereço MAC do dispositivo. Eles são projetados para serem globalmente únicos e, portanto, são uma escolha comum para sistemas distribuídos. Alguns aspectos dos UUIDs incluem:
- **Unicidade global**: A probabilidade de colisão de UUIDs é extremamente baixa, mesmo em sistemas distribuídos.
- **Independência do sistema**: UUIDs não dependem de um servidor central para a geração, tornando-os adequados para sistemas altamente distribuídos.
No entanto, os UUIDs podem ser menos eficientes em termos de armazenamento em comparação com IDs Serial, já que são mais longos. Além disso, a aleatoriedade na geração de UUIDs pode dificultar a ordenação eficiente em consultas de banco de dados.
PublicKey ( PK — Chave Pública)
A abordagem de combinar um ID Serial + um valor qualquer para ser usado como identificador público é uma técnica que permite a criação de identificadores únicos que preservam a ordem de criação, ao mesmo tempo em que fornecem um componente público para contextualização. Alguns aspectos dessa abordagem incluem:
- **Unicidade global**: Quando combinado com um hash único ou uma string, os identificadores resultantes são exclusivos em todo o sistema, assim como UUIDs.
- **Ordenação eficiente**: Como parte do identificador é gerado de forma sequencial, os IDs Serial combinados com um Hash/String podem ser usados para consultas ordenadas.
- **Contextualização**: A adição de um hash ou string como identificador público permite fornecer informações adicionais ou contexto sobre o registro.
Essa técnica é especialmente útil quando se deseja combinar a unicidade global com a capacidade de rastrear e contextualizar registros de forma eficiente.
Resumindo
IDs são rápidos e leves, porém não são tão seguros. UUIDs não são tão rápidos nem leves, mas resolvem problemas de colisão e segurança. Public Keys são rápidas, leves, sem colisões e seguras.
Então, eu me perguntava por que essa terceira abordagem não é tão comum. Foi assim que decidi testar as três e entender se vale a pena seguir com a abordagem de ter um ID + uma Public Key.
Como o teste foi feito
- Criei uma aplicação em Go para realizar inserções (inserts) e seleções (selects);
- Configurei um arquivo Docker Compose para iniciar três bancos de dados e as três aplicações correspondentes. Cada banco de dados possui suas próprias especificidades, como pode ser visto na imagem abaixo:
Observem que as diferenças entre cada modelo são bastante sutis
4. Configurei a aplicação para adicionar alguns dados no banco e, ao final de cada iteração de inserção, era necessário buscar a soma das notas dos alunos do último professor na tabela;
5. Monitorei o tempo de cada operação em cada modelo.
Conclusão
Como podemos notar, nem na escrita (gráfico de cima) nem na leitura (gráfico de baixo) houve grandes discrepâncias =/
Talvez devido à forma como testei, à massa de dados que não foi suficiente para que algum modelo se destacasse, ou mesmo devido à baixa cardinalidade, o resultado não foi muito satisfatório. No entanto, pelo menos conseguimos evidenciar o tamanho que cada abordagem ocupa no banco.
Pelo menos isso coincidiu com o esperado: UUID tem mais bytes, portanto, o banco ficou mais “pesado”. Isso pode ser mais um ponto positivo para a estratégia de ter a chave pública (PK) com um hash mais simplificado.
Plot twist
Pra não dizer que não teve nada, irei destacar uma peça no lego que não tinha usado ainda e achei bastante interessante, foi o XID. A ‘public key’ pode ser qualquer coisa, até mesmo um UUID, mas para esse teste, eu resolvi usar o XID.
Com o XID, foi possível obter uma chave pública curta, leve e com a possibilidade de ordenação. Bacana, não é? =O
Na API ficaria assim, por exemplo:
https://xpto.com/…/teacher/ck5pqkgjs0j1apumsoag
Se você já utilizou essa técnica de combinar um ID sequencial com uma chave pública, compartilhe sua experiência conosco nos comentários! Queremos ouvir sobre suas implementações e desafios.