21 puntos por GN⁺ 2024-07-06 | 4 comentarios | Compartir por WhatsApp
  • Los UUID se usan con frecuencia como clave primaria en tablas de bases de datos
    • Son fáciles de generar, fáciles de compartir entre sistemas distribuidos y garantizan unicidad
    • Considerando el tamaño de un UUID, uno podría preguntarse si esta es la elección correcta, pero muchas veces no podemos decidirlo
  • Este artículo no se centra en si “UUID es un formato adecuado para una clave”, sino en cómo usar de manera eficiente UUID como clave primaria en PostgreSQL

Usar PostgreSQL y UUID como clave primaria

  • ¿Qué es un UUID?
    • Los UUID se usan con frecuencia como clave primaria de tablas de bases de datos
    • Se pueden compartir fácilmente entre sistemas distribuidos y garantizan unicidad
    • Por el tamaño de los UUID, puede surgir la duda de si son adecuados, pero muchas veces no hay alternativa

Tipo de dato UUID en PostgreSQL

  • Guardar UUID como cadena

    • PostgreSQL ofrece el tipo de dato text para almacenar cadenas
    • Sin embargo, el tipo text no es adecuado para almacenar UUID
    • PostgreSQL ofrece el tipo de dato dedicado uuid para UUID
    • El tipo uuid es un tipo de dato de 128 bits, y requiere 16 bytes para almacenar un valor
    • El tipo text agrega una sobrecarga de 1 o 4 bytes
  • Resultados del experimento

    • Se crearon dos tablas para comparar: una con tipo text y otra con tipo uuid
    • Después de insertar 10,000,000 de filas, se comparó el tamaño de las tablas y de los índices
    • La tabla que usa tipo text es 54% más grande y el tamaño del índice es 85% mayor

UUID y los índices B-Tree

  • Índices B-Tree y UUID

    • Los UUID aleatorios no son adecuados para índices B-Tree
    • Los índices B-Tree funcionan bien con valores ordenados
    • UUID.randomUUID() de Java devuelve UUID v4, que es un valor seudoaleatorio
    • UUID v7 genera valores ordenados por tiempo, por lo que es adecuado para índices B-Tree
  • Uso de UUID v7

    • Para usar UUID v7 en Java se necesita la librería java-uuid-generator
    • Generar UUID v7 puede mejorar el rendimiento de inserción

Impacto de UUID v7 en el rendimiento de INSERT

  • Experimento
    • Se creó una tabla que usa UUID v7 y se insertaron 10,000 filas 10 veces para medir el rendimiento
    • Los resultados son algo aleatorios, pero insertar UUID v7 es aproximadamente 2 veces más rápido

Lecturas adicionales

  • Es posible que PostgreSQL 17 admita UUID v7 de forma nativa
  • Información sobre el formato UUID v7
  • El impacto de UUID en el rendimiento como clave primaria de base de datos

Resumen

  • Problema de la longitud de UUID

    • Incluso con optimización, UUID no es el tipo más óptimo como clave primaria
    • Si hay libertad de elección, conviene considerar otras opciones como TSID
  • Necesidad de optimización

    • Si se esperan conjuntos de datos grandes o alto tráfico, vale la pena considerar optimización
    • Cambiar la clave primaria es una tarea difícil, así que es importante configurarla correctamente desde el inicio
  • Precauciones

    • El autor no es un experto en PostgreSQL; solo comparte lo que aprendió
    • Si te resultó útil, agradecerá comentarios o feedback por Twitter

Resumen de GN⁺

  • Este artículo trata sobre formas eficientes de usar UUID como clave primaria en PostgreSQL
  • Muestra mediante experimentos que usar UUID v7 puede mejorar el rendimiento de inserción
  • Si se esperan conjuntos de datos grandes o alto tráfico, hace falta optimización
  • También vale la pena considerar otras opciones como TSID

4 comentarios

 
savvykang 2024-07-09

¿Es demasiado pedir una codificación base62 para uuid en lugar del formato estándar (hexadecimal + guiones)?

 
qurare 2024-07-08

uuidv7 es invencible
uuidv8+ es un "dios"

 
bbulbum 2024-07-08

El mayor obstáculo es que no es amigable para las personas... Yo todavía necesito bastante esa parte en muchos casos..

 
GN⁺ 2024-07-06
Opiniones de Hacker News
  • Se recomienda usar bigserial como clave primaria amigable con B-tree, y considerar UUID codificados como cadena como opción de localizador de registros externos

    • Si usuarios no técnicos van a citarlo, conviene considerar primero una opción simple como un localizador estilo PNR
    • No mezclar tipos de PK dentro del esquema de un servicio o aplicación
    • Si se usa UUIDv7 como identificador único, usarlo solo para datos que tengan un código temporal inherente
    • No usar hashids; no tiene calidad criptográfica y no resulta familiar para la gente común
    • Al codificar, no usar base64 ni alfabetos que incluyan guiones
  • Al diseñar el esquema de una base de datos, tener presentes los principios de separación de responsabilidades y simpatía mecánica

  • Los IDs aleatorios tipados de Stripe en realidad no son aleatorios

    • Incluyen metadatos, timestamps embebidos, shard y claves de referencia, información de versión, etc.
    • Personalmente, se prefiere un localizador bigserial+HMAC cifrado con AES y codificado en base58
  • En Postgres, los UUID aleatorios no son un gran problema

    • UUID (16 bytes) es más grande que serial (4 bytes) o bigserial (8 bytes), pero a nivel de tabla completa no es un problema importante
  • Antes de considerar serial vs. UUID aleatorio vs. UUID ordenado en Postgres, hay muchas otras cosas de las que preocuparse

  • Recientemente se eligió ULID como PK en Postgres, y este artículo fue de gran ayuda: https://brandur.org/nanoglyphs/026-ids

  • Se prefiere ULID porque es compatible con el tipo UUID y, como tiene un timestamp incorporado, al ordenar por ID también se ordena por timestamp

  • Estaría bien incluir también int64 en la comparación para poder comparar la sobrecarga de UUID con la del enfoque tradicional

  • El rendimiento de inserción es una mala forma de evaluar el rendimiento

    • El rendimiento del B-Tree es mejor al insertar, pero queda la duda de cómo se comporta en transacciones a gran escala
  • En SQLite se prefiere UUID4 porque hay menos probabilidad de colisiones en la caché de páginas durante el bloqueo de transacciones

    • Algo similar podría aplicar también en sistemas Postgres
  • Se prefieren las claves primarias enteras autoincrementales

    • Son fáciles de entender y simples de ordenar
    • En proyectos de lotes a gran escala, se puede guardar la última clave primaria y traer todo lo que sea mayor que ella
  • El benchmark de tiempo de inserción de UUIDv7 incluye el tiempo de generación del UUID

    • Sería bueno ver por separado solo el costo de actualización del índice
  • Es poco probable que PostgreSQL 17 incluya soporte para UUIDv7

    • El committer fue removido recientemente y la versión 17 ya está en congelamiento de funcionalidades
  • Se empezó a usar python-ulid, y ULID es superior a UUID

  • Como el enlace al estándar UUID v7 está desactualizado, conviene consultar RFC 9562: https://datatracker.ietf.org/doc/html/rfc9562