0011. UUID vs BIGINT: qué identificador usar en cada caso¶
Estado: Aceptado Fecha: 2026-09-03 Autor: Duval Alcivar
Contexto¶
Con 14 microservicios y 3 bases de datos, hay que definir claramente cuándo usar UUID y cuándo BIGINT para identificadores. Cada error crea acoplamiento entre servicios o rompe el aislamiento por empresa.
El ADR 0003 ya establece que la correlación entre servicios es por UUID, y
el ADR 0004 define id como UUID PK e empresa_id como BIGINT. Este ADR
completa la regla con ejemplos concretos.
El aislamiento por empresa (RLS) se trata en el ADR 0012.
Decisión¶
La clave: ¿Es catálogo o entidad de negocio?¶
CATÁLOGO = BIGINT (pocos registros, finitos, rara vez cambian)
empresas: 5 registros → BIGINT
sucursales: 12 registros → UUID (*)
paises: 200 registros → BIGINT
canales: 10 registros → BIGINT
bodegas: 8 registros → BIGINT
() Las sucursales son la excepción: aunque son pocas, se referencian entre
servicios* (selector de sucursal en el token, consumidores), así que su id
es UUID.
¿Por qué? Son pocos, finitos, nunca llegan a millones. BIGINT es más pequeño (8 bytes vs 16 bytes) y más eficiente para filtros.
ENTIDAD DE NEGOCIO = UUID (muchos registros, crece, se referencia entre servicios)
clientes: 10,000+ registros → UUID
productos: 5,000+ registros → UUID
facturas: 50,000+ registros → UUID
pedidos: 100,000+ registros → UUID
movimientos: 500,000+ registros → UUID
¿Por qué? Crecen, pueden ser millones, se referencian entre servicios. UUID es único globalmente y se genera sin conexión a la DB.
Ejemplo simple: Un pedido¶
CREATE TABLE erp.trx_pedidos (
-- PK del pedido (entidad de negocio)
id UUID PRIMARY KEY, -- UUID: es grande y se referencia entre servicios
-- Referencia a empresa (catálogo pequeño)
empresa_id BIGINT NOT NULL, -- BIGINT: es pequeño
-- Referencia a cliente (entidad de negocio)
cliente_id UUID NOT NULL, -- UUID: es grande y cross-service
-- Referencia a sucursal (selector de sucursal en el token)
sucursal_id UUID NOT NULL, -- UUID: se referencia entre servicios
-- Referencia a usuario (entidad central, cross-service)
usuario_id UUID NOT NULL, -- UUID: se referencia entre servicios
-- Datos de negocio
fecha_pedido DATE,
total NUMERIC(12,2)
);
¿Por qué esta combinación?
| Campo | Tipo | Tabla origen | ¿Por qué? |
|---|---|---|---|
id |
UUID | trx_pedidos | PK del pedido (entidad grande) |
empresa_id |
BIGINT | empresas | Catálogo pequeño (5 empresas) |
cliente_id |
UUID | mae_clientes | Entidad grande (10k clientes), cross-service |
sucursal_id |
UUID | mae_sucursales | Se referencia entre servicios |
usuario_id |
UUID | mae_usuarios | Entidad central, cross-service |
¿Por qué NO usar UUID para empresa_id?¶
Si mae_empresas tuviera UUID:
TABLA: mae_empresas
id = UUID('a1b2c3d4-e5f6-7890-abcd-ef1234567890') razon_social = "Sigfa S.A."
id = UUID('e5f6g7h8-i9j0-klmn-opqr-stuvwxyz1234') razon_social = "SigfaPro Cía."
Y en mae_clientes:
TABLA: mae_clientes
id = UUID('x1y2...') empresa_id = UUID('a1b2c3d4-e5f6-7890-abcd-ef1234567890')
Problemas:
- Filtros más lentos — PostgreSQL filtra por
empresa_iden CADA query. BIGINT (8 bytes) es más rápido que UUID (16 bytes) - Más espacio — Cada registro guarda 8 bytes extra por cada referencia
- Menos legible — ¿Prefieres ver
empresa_id = 5oempresa_id = a1b2c3d4-e5f6-7890-abcd-ef1234567890? - No necesitas unicidad global —
empresa_idsolo necesita ser único dentro de la tablamae_empresas, no globalmente
¿Cuándo SÍ usar UUID para referencias?¶
Cuando la entidad es grande y se referencia entre servicios:
TABLA: mae_clientes
id = UUID('a1b2c3d4-...') nombre = "Juan Pérez"
id = UUID('e5f6g7h8-...') nombre = "María García"
Y en trx_pedidos:
TABLA: trx_pedidos
id = UUID('x1y2...') cliente_id = UUID('a1b2c3d4-...')
¿Por qué UUID aquí?
- 10,000+ clientes — necesitas unicidad global
- svc-pedidos referencia a svc-clientes — cross-service
- UUID se genera sin DB — puedes crearlo en el frontend
- UUID no revela volúmenes — no sabes cuántos clientes tienes
Resumen: UUID vs BIGINT¶
| Pregunta | Respuesta |
|---|---|
| ¿Es un catálogo pequeño (< 1000 registros)? | BIGINT |
| ¿Se referencia entre servicios? | UUID |
| ¿Necesitas unicidad global? | UUID |
Ejemplos por servicio¶
1. svc-identidad: empresas, usuarios, sucursales¶
Tabla core.identidad.mae_empresas:
CREATE TABLE core.identidad.mae_empresas (
id BIGINT GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY, -- BIGINT identity (catálogo pequeño)
razon_social TEXT NOT NULL,
ruc TEXT NOT NULL,
is_activo BOOLEAN DEFAULT TRUE
);
Tabla core.identidad.mae_usuarios:
CREATE TABLE core.identidad.mae_usuarios (
id UUID PRIMARY KEY, -- UUID (entidad central)
username TEXT UNIQUE NOT NULL,
email TEXT UNIQUE NOT NULL,
password TEXT NOT NULL, -- hash Argon2id
password_temp BOOLEAN NOT NULL DEFAULT TRUE,
entidad_id UUID NOT NULL, -- FK → mae_entidades (persona natural o jurídica, ADR 0022)
is_activo BOOLEAN DEFAULT TRUE
);
Tabla core.identidad.rel_usuario_sucursal (relación N:M):
CREATE TABLE core.identidad.rel_usuario_sucursal (
id UUID PRIMARY KEY, -- UUID (relación)
usuario_id UUID NOT NULL, -- FK intra-servicio (mismo servicio)
sucursal_id UUID NOT NULL, -- FK intra-servicio (mismo servicio)
is_activo BOOLEAN DEFAULT TRUE
);
2. svc-clientes (CRM): mae_clientes¶
CREATE TABLE crm.clientes.mae_clientes (
id UUID PRIMARY KEY, -- UUID (entidad central)
empresa_id BIGINT NOT NULL, -- BIGINT (catálogo pequeño)
nombre TEXT NOT NULL,
email TEXT,
telefono TEXT,
created_at TIMESTAMPTZ DEFAULT NOW(),
updated_at TIMESTAMPTZ DEFAULT NOW(),
deleted_at TIMESTAMPTZ NULL
);
3. svc-pedidos (ERP): trx_pedidos¶
CREATE TABLE erp.pedidos.trx_pedidos (
id UUID PRIMARY KEY, -- UUID (entidad del pedido)
empresa_id BIGINT NOT NULL, -- BIGINT (catálogo pequeño)
cliente_id UUID NOT NULL, -- UUID de svc-clientes (cross-service)
vendedor_id UUID NOT NULL, -- UUID de svc-fuerza-ventas (cross-service)
sucursal_id UUID NOT NULL, -- UUID de svc-identidad
usuario_id UUID NOT NULL, -- UUID de svc-identidad (entidad central)
fecha_pedido DATE NOT NULL,
total NUMERIC(12,2) NOT NULL,
created_at TIMESTAMPTZ DEFAULT NOW()
);
¿Por qué cliente_id y sucursal_id son UUID?
| Campo | Tipo | Origen | Por qué |
|---|---|---|---|
cliente_id |
UUID | svc-clientes (otro servicio) | Cross-service, entidad grande |
vendedor_id |
UUID | svc-fuerza-ventas (otro servicio) | Cross-service, entidad grande |
sucursal_id |
UUID | svc-identidad | Se referencia entre servicios (token/consumidores) |
usuario_id |
UUID | svc-identidad (entidad central) | Cross-service, se referencia desde muchos servicios |
Reglas no negociables¶
- PK = UUID en toda tabla; única excepción el catálogo de tenencia
mae_empresas→ BIGINT identity empresa_id= BIGINT en toda tabla- Cross-service = UUID — nunca FK entre servicios
- Dentro del mismo servicio = el tipo de la PK destino: FK a
mae_empresases BIGINT (empresa_id); el resto de FKs son UUID
Consecuencias¶
- Toda tabla nueva debe tener
id UUID PKeempresa_id BIGINT NOT NULL - Toda referencia a entidad de otro servicio usa UUID, nunca BIGINT
- Toda FK dentro del mismo servicio usa BIGINT (catálogo) o UUID (entidad)
- El frontend recibe UUID en respuestas, nunca IDs numéricos de otros servicios
- El modelo de datos de
svc-identidadque aplica estas reglas está definido en los ADRs 0005 (mae_usuariosUUID PK,rel_usuario_sucursalUUID PK), 0007 (cat_permisosUUID PK) y 0004 (mae_empresasBIGINT PK) de svc-identidad.