Database Design Mistakes I Made So You Don't Have To \u2014 TXT1.ai

March 2026 · 15 min read · 3,636 words · Last Updated: March 31, 2026Advanced

💡 Key Takeaways

  • The "I'll Just Use UUIDs Everywhere" Disaster
  • Premature Normalization: When Third Normal Form Becomes Your Enemy
  • The NULL Nightmare: When Optional Becomes Impossible
  • Index Overload: When More Isn't Better
I'll write this expert blog article for you as a comprehensive HTML piece from a specific persona's perspective.

Hace tres años, vi cómo la base de datos de nuestra startup se detuvo a las 2:47 AM el Black Friday. Teníamos 50,000 usuarios concurrentes, $2 millones en transacciones pendientes y una consulta que tardaba 45 segundos en devolver la disponibilidad de productos. Nuestro CTO estaba gritando en Slack. Nuestros inversionistas estaban llamando. Y yo miraba un esquema que había diseñado seis meses antes, dándome cuenta de que cada decisión "inteligente" que había tomado nos estaba costando aproximadamente $8,000 por minuto en ingresos perdidos.

💡 Conclusiones Clave

  • El Desastre de "Solo Usaré UUIDs en Todas partes"
  • Normalización Prematura: Cuando la Tercera Forma Normal se Convierte en Tu Enemigo
  • La Pesadilla NULL: Cuando Opcional se Convierte en Imposible
  • Sobrecarga de Índices: Cuando Más No es Mejor

Soy Marcus Chen, y he pasado los últimos doce años como arquitecto de bases de datos, trabajando con todos, desde startups de SaaS hasta empresas de Fortune 500. He diseñado esquemas para sistemas que manejan 500 millones de transacciones diarias, optimizado consultas que redujeron 200ms de rutas críticas, y sí—he cometido prácticamente todos los errores de diseño de bases de datos del libro. ¿Ese incidente del Black Friday? Me enseñó más sobre diseño de bases de datos que mi carrera completa en ciencias de la computación.

Hoy, soy el Arquitecto Principal de Bases de Datos en TXT1.ai, donde procesamos más de 3 mil millones de mensajes de texto al año a través de nuestra plataforma de comunicación impulsada por IA. Pero llegué aquí avanzando a través de los fracasos, y quiero compartir las lecciones costosas que aprendí para que puedas evitar los ataques de pánico a las 2 AM y las llamadas de inversionistas enojados.

El Desastre de "Solo Usaré UUIDs en Todas partes"

Déjame comenzar con lo que llamo mi error de $40,000. En 2019, estaba diseñando un sistema de gestión de relaciones con clientes para una empresa de comercio electrónico de tamaño mediano. Acababa de leer una entrada de blog sobre cómo los UUIDs eran la forma "moderna" de manejar las claves primarias—no más enteros autoincrementables, no más exposición de ID secuenciales, perfecto para sistemas distribuidos. Estaba convencido.

Así que hice que cada clave primaria en el sistema fuera un UUID. ¿Tabla de usuarios? UUID. ¿Tabla de pedidos? UUID. ¿Artículos de línea de pedido? Lo adivinaste—UUID. Me sentía como un genio. El esquema se veía limpio, no había vulnerabilidades de ID secuenciales, y podría generar IDs del lado del cliente si fuera necesario. ¿Qué podría salir mal?

Todo. Absolutamente todo salió mal.

En seis meses, el tamaño de nuestra base de datos había aumentado a 340GB cuando debería haber sido alrededor de 180GB. El rendimiento de las consultas se estaba degradando semana a semana. El tamaño de nuestros índices era masivo—el índice de la tabla de pedidos solo tenía 12GB. Las uniones entre pedidos y artículos de línea que deberían haber tomado 50ms estaban tomando 800ms. La base de datos estaba gastando enormes cantidades de tiempo en E/S de disco, y nuestros costos de AWS RDS casi se habían duplicado.

Esto es lo que aprendí de la manera difícil: Los UUIDs son de 128 bits (16 bytes) en comparación con un entero de 4 bytes o un bigint de 8 bytes. Eso es 4x el almacenamiento para cada clave primaria. Pero el verdadero problema no es el almacenamiento—es la fragmentación del índice. Los UUIDs son aleatorios, lo que significa que cada inserción provoca escrituras aleatorias en tus índices B-tree. Con enteros secuenciales, nuevas filas se agregan al final del índice. Con UUIDs, la base de datos está constantemente reequilibrando toda la estructura del índice.

Medimos el impacto: insertar 100,000 filas con IDs enteros tomó 8 segundos. La misma operación con UUIDs tomó 34 segundos. Esa es una penalización de rendimiento de 4.25x solo por la elección de la clave primaria. Cuando estás procesando 50,000 pedidos al día, eso se suma rápidamente.

La solución nos costó tres semanas de tiempo de desarrollo y requirió una migración cuidadosamente orquestada durante una ventana de mantenimiento. Nos movimos a claves primarias bigint para tablas de alto volumen y mantenimos UUIDs solo para las tablas donde realmente necesitábamos identificadores globalmente únicos en sistemas distribuidos—lo que resultó ser exactamente dos tablas de cuarenta y siete.

Mi regla ahora: Utiliza enteros o bigints autoincrementables para claves primarias a menos que tengas una razón específica y documentada para usar UUIDs. Y "parece más moderno" no es una razón documentada.

Normalización Prematura: Cuando la Tercera Forma Normal se Convierte en Tu Enemigo

Recien salido de la universidad, estaba obsesionado con la normalización. Me había memorizado todas las formas normales, podía recitar las reglas de Codd en mis sueños, y creía que una base de datos correctamente normalizada era el pináculo de la excelencia del diseño. Así que cuando diseñé mi primer sistema de producción—una plataforma de gestión de contenido—normalicé todo hasta la tercera forma normal y más allá.

"Cada decisión de base de datos 'inteligente' que tomes hoy es una posible crisis a las 2 AM dentro de seis meses. Diseña para el sistema que tendrás, no para el sistema que deseas."

Tenía una tabla de usuarios, una tabla de direcciones de usuarios (porque los usuarios pueden tener múltiples direcciones), una tabla de números de teléfono de usuarios (¡múltiples teléfonos!), una tabla de preferencias de usuarios, una tabla de configuraciones de usuarios y una tabla de metadatos de usuarios. Cargar el perfil de un solo usuario requería unir seis tablas. Estaba tan orgulloso de lo "limpio" que todo se veía.

Luego lanzamos. La página del perfil del usuario—la página más accesada de toda la aplicación—estaba tardando 1.2 segundos en cargar. Estábamos haciendo seis uniones por cada vista de página, y con 10,000 usuarios activos diarios, eso significaba 60,000 uniones por día solo para las vistas de perfil. La CPU de la base de datos estaba constantemente por encima del 70%.

La llamada de atención llegó cuando nuestro desarrollador principal me apartó y me mostró el plan de ejecución de la consulta. "Marcus," dijo, "estamos uniendo seis tablas para mostrar el nombre, el correo electrónico y el número de teléfono de un usuario. Esto es una locura." Tenía razón. Había optimizado por pureza teórica en lugar de rendimiento práctico.

Desnormalizamos estratégicamente. La dirección principal del usuario volvió a la tabla de usuarios. ¿Su número de teléfono principal? Lo mismo. Mantenemos las tablas separadas para direcciones y números de teléfono adicionales, pero el 94% de nuestros usuarios solo tenían uno de cada uno. Ese único cambio redujo nuestro tiempo promedio de consulta de la página de perfil de 1.2 segundos a 180ms—una mejora del 85%.

Esto es lo que aprendí: La normalización es una herramienta, no una religión. La tercera forma normal es un gran punto de partida, pero el rendimiento en el mundo real a menudo requiere desnormalización estratégica. Ahora sigo lo que llamo la "regla de desnormalización 80/20": si el 80% de las consultas necesitan datos de múltiples tablas, esos datos probablemente pertenezcan a una sola tabla. Mido los patrones de consulta en producción y desnormalizo en función del uso real, no de la pureza teórica.

La clave es saber cuándo desnormalizar. Las tablas de alta lectura y bajo escritura son candidatas perfectas. Perfiles de usuarios, catálogos de productos, datos de configuración—todos estos son grandes lugares para desnormalizar. ¿Tablas de transacciones con altos volúmenes de escritura? Mantenlos normalizados para evitar anomalías de actualización.

La Pesadilla NULL: Cuando Opcional se Convierte en Imposible

Solía amar las columnas anulables. Parecían tan flexibles, tan acomodadas. ¿Un usuario podría no tener un segundo nombre? Hazlo anulable. ¿Un pedido podría no tener un código de descuento? Anulable. ¿Un producto podría no tener un peso? Captaste la idea.

Tipo de Clave PrimariaTamaño de AlmacenamientoRendimiento del ÍndiceMejor Caso de Uso
INT autoincrementable4 bytesExcelente (secuencial)Sistemas de servidor único, tablas de alto volumen
BIGINT autoincrementable8 bytesExcelente (secuencial)Sistemas de servidor único a gran escala
UUID (v4)16 bytesPobre (aleatorio)Sistemas distribuidos, IDs sensibles a la seguridad
ULID/UUID (v7)16 bytesBueno (ordenado por tiempo)Sistemas distribuidos que necesitan ordenabilidad
Claves CompuestasVaríaJusto a BuenoRelaciones naturales, sistemas multi-inquilino

En un proyecto particularmente desastroso, diseñé un sistema de gestión de inventarios donde aproximadamente el 60% de las columnas en todas las tablas eran anulables. Parecía razonable—no todos los campos tendrían siempre datos, ¿verdad? ¿Por qué forzar valores por defecto cuando NULL comunica claramente "sin valor"?

Los problemas comenzaron de inmediato. Las consultas se convirtieron en un campo minado de comprobaciones NULL. ¿Quieres encontrar todos los productos sin peso? Pensarías que "WHERE weight IS NULL" funcionaría, pero ¿qué pasa con los productos donde el peso se estableció explícitamente en cero? Ahora necesitas "WHERE weight IS NULL OR weight = 0". ¿Quieres sumar los totales de pedidos? Mejor usa COALESCE o tu SUM podría devolver NULL si cualquier valor individual es NULL.

🛠 Explora Nuestros Herramientas

Minificador de JavaScript - Comprime Código JS Gratis → Registro de cambios — txt1.ai → Minificador de CSS - Comprime CSS Online Gratis →

B

T

Written by the Txt1.ai Team

Our editorial team specializes in writing, grammar, and language technology. We research, test, and write in-depth guides to help you work smarter with the right tools.

Share This Article

Twitter LinkedIn Reddit HN

Related Tools

Code Diff Checker - Compare Two Files Side by Side Free Use Cases - TXT1 HTML to PDF Converter — Free, Accurate Rendering

Related Articles

AI Coding Tools in 2026: An Honest Assessment — txt1.ai TypeScript vs JavaScript in 2026: Which Should You Learn? — txt1.ai Clean Code: 10 Principles That Make You a Better Developer — txt1.ai

Put this into practice

Try Our Free Tools →

🔧 Explore More Tools

Color ConverterHtml SitemapWord CounterDevtoys AlternativeCode DiffAi Unit Test Generator

📬 Stay Updated

Get notified about new tools and features. No spam.