Quando os computadores começaram a se conectar em rede de verdade, apareceu um problema simples mas bem tenso: como garantir que dois dispositivos diferentes, em lugares diferentes do mundo, não vão gerar o mesmo identificador?
Pensa só: dois servidores, um em Tóquio e outro em Berlim, criando identificadores pra objetos de forma independente. Se eles gerarem o mesmo ID — os dados podem se misturar, sobrescrever e o sistema pode cair.
Foi aí que, nos anos 90, na época do boom dos sistemas distribuídos e protocolos de rede, a galera da Microsoft e da Open Software Foundation (OSF) teve a ideia do GUID — Globally Unique Identifier, ou identificador globalmente único.
O GUID (no padrão ISO é chamado de UUID, Universally Unique Identifier) é um número de 128 bits, que parece mais ou menos assim:
550e8400-e29b-41d4-a716-446655440000
É tipo uma impressão digital digital: tão longo e aleatório que a chance de colisão (dois IDs iguais) é praticamente zero.
Ele é criado usando:
- tempo,
- números aleatórios,
- endereço MAC do dispositivo (nas versões antigas),
- e até funções hash criptográficas.
Por que isso era importante? Porque o GUID permitiu criar identificadores únicos sem servidor central, sem coordenação, sem locks e sem atrasos. Isso salvou a vida de:
- bancos de dados distribuídos,
- protocolos de rede,
- sistemas de documentos,
- e claro, APIs modernas.
UUID no PostgreSQL
GUID/UUID é usado em tudo quanto é lugar — de PostgreSQL até serviços em nuvem. Eles são os construtores invisíveis da internet moderna: sem eles, juntar o mundo seria bem mais difícil.
No fim das contas, é só um número aleatório bem grande de 16 bytes, escrito em hexadecimal. Só um número inteiro bem grandão.
Esse tipo de dado é perfeito se você precisa garantir unicidade dos valores no sistema todo, sem depender de um gerador centralizado de IDs. Isso é especialmente útil em sistemas distribuídos ou quando os dados são gerados em servidores diferentes.
Por que não usar só INTEGER?
Parece que não faz sentido usar UUID se dá pra usar um número auto-incremental como identificador, né? Bora ver:
Unicidade global: Se seu banco rodar em vários servidores, garantir unicidade com INTEGER é complicado. Com UUID isso é resolvido.
Segurança e esconder dados: UUID é bem mais difícil de adivinhar do que um número sequencial. Isso diminui o risco de vazar info por IDs previsíveis (tipo /users/1, /users/2).
Sistemas distribuídos: Se os dados são gerados em partes diferentes do sistema, um INTEGER auto-incremental não serve sem uma sincronização complicada.
Outra vantagem do UUID — é padrão, suportado em várias linguagens de programação e sistemas de armazenamento.
Vantagens de usar UUID
Os principais pontos positivos:
- Unicidade: garante que o identificador é único, mesmo se os dados forem criados em servidores ou sistemas diferentes.
- Flexibilidade: dá pra usar como chave primária, chave estrangeira e outras paradas.
- Escalabilidade: ótimo pra trabalhar com bancos de dados distribuídos.
Mas o UUID também tem seus pontos negativos:
- Tamanho:
UUIDocupa mais espaço na memória (16 bytes) do queINTEGER(4 bytes). - Leitura: é mais difícil de ler e decorar.
Gerando UUID no PostgreSQL
Função nativa gen_random_uuid()
No PostgreSQL a partir da versão 13 tem a função nativa gen_random_uuid() pra gerar UUID aleatório. Essa função retorna um identificador único, que você pode usar como valor pra coluna do tipo UUID.
Exemplo:
SELECT gen_random_uuid();
Resultado:
d17fc23b-22e5-4fcb-bf86-1b4c766d77b7
Confere se a extensão pgcrypto tá instalada (pra PSQL 1-12)
Nas versões antigas do PostgreSQL (antes da 13) a função gen_random_uuid() só aparece depois de instalar a extensão pgcrypto. Se no trampo te obrigarem a usar, dá pra resolver rodando:
CREATE EXTENSION IF NOT EXISTS "pgcrypto";
Assim você pode usar a geração de UUID aleatório.
Usando UUID como chave estrangeira
UUID é bem prático pra criar relações entre tabelas. Imagina que você tem uma tabela de usuários:
| id | name | |
|---|---|---|
| d17fc23b-22e5-4fcb-bf86-1b4c766d77b7 | Alice | alice@example.com |
| a1d3e15a-abc1-4b51-a320-2d4c859f7467 | Bob | bob@example.com |
| 3c524998-5c24-4e73-836d-a4c6bb3cafcd | Charlie | charlie@example.com |
Criando a tabela orders
Bora criar a tabela orders, onde user_id vai ser a chave estrangeira apontando pro id da tabela users.
| order_id | user_id | order_date |
|---|---|---|
| 1a5b7d9c-b1a2-4f8e-9e7a-0a1111111111 | d17fc23b-22e5-4fcb-bf86-1b4c766d77b7 | 2024-10-15 10:00:00 |
| 2b6c8e0d-c2b3-5a9f-af8b-1b2222222222 | a1d3e15a-abc1-4b51-a320-2d4c859f7467 | 2024-10-15 10:05:00 |
| 3c7d9f1e-d3c4-6baf-bc9c-2c3333333333 | 3c524998-5c24-4e73-836d-a4c6bb3cafcd | 2024-10-15 10:10:00 |
| 4d8eaf2f-e4d5-7cb0-cdab-3d4444444444 | d17fc23b-22e5-4fcb-bf86-1b4c766d77b7 | 2024-10-15 10:15:00 |
| 5e9fb030-f5e6-8dc1-debc-4e5555555555 | a1d3e15a-abc1-4b51-a320-2d4c859f7467 | 2024-10-15 10:20:00 |
O campo user_id tá ligado ao campo id da tabela users, o que permite criar relações entre usuários e seus pedidos.
Selecionando dados com JOIN
Vamos ver como os dados das tabelas users e orders se relacionam:
SELECT
u.id AS user_id,
u.name,
o.order_id,
o.order_date
FROM users u
JOIN orders o ON u.id = o.user_id;
Resultado:
| user_id | name | order_id | order_date |
|---|---|---|---|
| d17fc23b-22e5-4fcb-bf86-1b4c766d77b7 | Alice | a1d3e15a-abc1-4b51-a320-2d4c859f7467 | 2024-10-20 12:34:56 |
Cenários principais de uso do UUID
Identificadores de usuários e pedidos: em sistemas distribuídos, onde os dados podem vir de várias fontes.
Marcação pra API: UUID é muito usado em REST API pra identificar entidades.
Sincronização global de dados: tipo quando os dados vêm de vários servidores.
Erros comuns e particularidades
Tentar gerar UUID na mão: melhor usar funções nativas como gen_random_uuid() pra não dar ruim.
Uso exagerado: não use UUID onde um INTEGER auto-incremental já resolve. Tipo em tabelas locais que nunca vão escalar.
Tamanho: UUID ocupa mais espaço, o que pode impactar a performance das queries, principalmente nos índices.
GO TO FULL VERSION