Volver al Blog
Ingeniería 30 de junio de 2025 · 14 min lectura

Por Qué Todo Experto en Migración de Bases de Datos Empezó con Clave-Valor: De Globals MUMPS a D1

GM

Gonzalo Monzón

Fundador & Arquitecto Principal

En 1997, mi primera base de datos en producción fue un global MUMPS — un árbol clave-valor jerárquico almacenado en un HP 9000 con MSM. En 2024, mi base de datos en producción es Cloudflare D1 — SQLite en el edge. Entre esos dos puntos, migré datos a través de Caché, SQL Server, PostgreSQL, y más variaciones de "guarda esto, recupera aquello" de las que me gustaría contar. La lección sorprendente: toda base de datos es fundamentalmente un almacén clave-valor con distintos niveles de ceremonia encima. Entender esto cambia cómo piensas sobre cada migración que vayas a hacer.

El Global: Donde Todo Empezó

Los globals de MUMPS son la estructura de datos más simple posible que podía funcionar para un hospital. Un global es un array persistente, jerárquico y disperso — esencialmente un árbol donde cada nodo tiene una clave y opcionalmente un valor.

Un registro de paciente se veía así:

^PACIENTE(12345,"NOMBRE") = "García López, María"
^PACIENTE(12345,"FNAC") = "19450312"
^PACIENTE(12345,"ALERGIAS",1) = "Penicilina"
^PACIENTE(12345,"ALERGIAS",2) = "Sulfamidas"
^PACIENTE(12345,"LAB","20130415","GLU") = 98
^PACIENTE(12345,"LAB","20130415","HB") = 14.2
^PACIENTE(12345,"LAB","20130416","GLU") = 105

Sin esquema. Sin tipos. Sin claves foráneas. Sin ALTER TABLE. Simplemente escribías datos con una clave jerárquica y los leías de vuelta. La clave en sí era el esquema — la convención de nomenclatura determinaba el modelo de datos. Y funcionó durante décadas en hospitales gestionando millones de registros de pacientes.

Por Qué los Globals Eran Brillantes (y Peligrosos)

El modelo de globals tenía fortalezas reales que las bases de datos NoSQL modernas redescubrieron de forma independiente:

  • Flexibilidad de esquema: Añadir un campo nuevo era trivial — solo escribir en una nueva ruta de clave. Sin scripts de migración, sin downtime, sin versionado de esquemas. Si el paciente 12345 necesitaba un campo "MODELO_MARCAPASOS", ponías ^PACIENTE(12345,"MODELO_MARCAPASOS") = "Medtronic MiniMed" y existía
  • Datos dispersos: No todos los pacientes tienen alergias. No todas las visitas tienen resultados de laboratorio. En un modelo relacional, necesitas columnas nullable o tablas de unión. En globals, los datos ausentes simplemente no existen como clave — ocupan cero espacio
  • Jerarquías naturales: Paciente → visitas → resultados de laboratorio → pruebas individuales mapea perfectamente al árbol de globals. Sin JOINs necesarios. Recorrer el historial de un paciente era un único $ORDER bajando por el árbol
  • Acceso O(1): Recuperar un valor conocido — ^PACIENTE(12345,"NOMBRE") — era una única búsqueda en B-tree. Sin optimizador de consultas. Sin plan de ejecución. Direccionamiento directo

El peligro era igualmente real: la lógica de aplicación era el esquema. No había enforcement de integridad de datos a nivel de base de datos. Si un desarrollador almacenaba una fecha como "15 de Marzo" en lugar de "20130315", la base de datos lo aceptaba silenciosamente. La consistencia dependía enteramente de convenciones de código disciplinadas, transmitidas como conocimiento institucional entre programadores MUMPS. Un desarrollador descuidado podía corromper el esquema implícito de un subsistema entero.

Caché: La Base de Datos Puente

InterSystems Caché fue el sucesor evolutivo de MSM — mantenía el modelo de almacenamiento por globals pero añadía una capa de proyección SQL encima. Podías acceder a los mismos datos como globals (para código MUMPS legacy) o como tablas SQL (para aplicaciones modernas).

Este modelo de acceso dual fue revolucionario para las migraciones. Durante mis años dando soporte a sistemas sanitarios con Caché, aprendí lo que ahora considero el principio fundamental de la migración de bases de datos: no migras los datos — añades una nueva capa de acceso.

250 Clientes, Dos Paradigmas

En el punto álgido de mi trabajo con Caché, daba soporte a aproximadamente 250 conexiones concurrentes a un sistema sanitario funcionando 24/7. Algunos de esos clientes eran terminales MUMPS accediendo a globals directamente. Otros eran aplicaciones web consultando vistas SQL. Ambos accedían a los mismos datos subyacentes.

Esto me enseñó algo que la mayoría de ingenieros de bases de datos nunca experimentan: los mismos datos, accedidos a través de diferentes paradigmas, revelan diferentes problemas. Una consulta que era instantánea vía acceso por global ($GET(^PACIENTE(12345,"NOMBRE")) — búsqueda directa por clave) podía ser lenta vía SQL (SELECT nombre FROM pacientes WHERE id = 12345 — parseo de consulta, plan, ejecución, retorno). A la inversa, una consulta agregada trivial en SQL (SELECT AVG(glucosa) FROM resultados_lab WHERE fecha > '2013-01-01') requeriría un recorrido completo del global en MUMPS.

La lección: los modelos de almacenamiento son patrones de acceso. Los mismos bytes en disco pueden ser rápidos o lentos dependiendo de cómo preguntes por ellos. Migrar no va de mover datos — va de cambiar qué patrones de acceso son rápidos.

El Patrón EAV: NoSQL Dentro de SQL Server

En Werfen (una multinacional de diagnóstico médico), me encontré con el patrón Entity-Attribute-Value (EAV) en una aplicación Delphi respaldada por SQL Server. El producto, MediVector, gestionaba configuraciones de dispositivos médicos para más de 40 hospitales.

El esquema EAV se veía así:

CREATE TABLE atributos_dispositivo (
  entity_id    INT,          -- qué dispositivo
  atributo     VARCHAR(100), -- qué propiedad
  valor        NVARCHAR(MAX) -- el valor (siempre string)
);

-- Un dispositivo podía tener:
-- (1001, 'modelo', 'ACLTOP 700')
-- (1001, 'numero_serie', 'WF-2019-44821')
-- (1001, 'version_firmware', '3.2.1')
-- (1001, 'ultima_calibracion', '2024-01-15')
-- (1001, 'hospital', 'Hospital del Mar')
-- (1001, 'departamento', 'Hematología')

Si esto te suena familiar, es porque EAV es globals con overhead de SQL. La misma idea — entidad + ruta de atributo = valor. Pero en lugar del acceso directo al B-tree de los globals, cada lectura pasa por el parser SQL, el optimizador y el executor. Obtienes la flexibilidad del almacenamiento clave-valor pero pagas el coste completo de la infraestructura relacional.

La Migración: De EAV a REST Normalizado

Mi trabajo en Werfen era migrar MediVector de la arquitectura Delphi/EAV a una API REST en .NET Core con un esquema normalizado adecuado. La migración reveló el mismo patrón que había visto con MUMPS → SQL:

  1. Descubrir el esquema implícito. Las tablas EAV no tienen esquema — el esquema vive en el código de la aplicación. Tuve que leer miles de líneas de Delphi para entender qué atributos estaban siempre presentes (obligatorios), cuáles eran opcionales y cuáles eran calculados. Es exactamente el mismo trabajo que hice haciendo ingeniería inversa de globals MUMPS
  2. Normalizar gradualmente. En vez de una migración big-bang, creé vistas SQL que proyectaban los datos EAV como tablas normalizadas. La vieja app Delphi seguía escribiendo filas EAV; la nueva API .NET leía de las vistas normalizadas. ¿Te suena? Es la Higuera Estranguladora otra vez — mismo patrón, diferente base de datos
  3. Preservar los patrones de acceso. La aplicación antigua estaba optimizada para "muéstrame todos los atributos del dispositivo X" (una única consulta WHERE entity_id = 1001). El nuevo esquema estaba optimizado para "muéstrame todos los dispositivos con firmware desactualizado" (una consulta con columna indexada). Ambos tenían que funcionar durante la transición

El Círculo se Cierra: SQLite en el Edge

Hoy, en Cadences Lab, nuestra base de datos en producción es Cloudflare D1 — SQLite corriendo en el edge de la red de Cloudflare. Y aquí está el giro irónico: el motor de almacenamiento de SQLite es, en su núcleo, un almacén clave-valor B-tree.

Cuando escribes INSERT INTO usuarios (nombre, email) VALUES ('Ana', '[email protected]'), SQLite lo almacena como un par clave-valor donde la clave es el rowid y el valor son los datos serializados de la fila. La capa SQL es ceremonia — ceremonia útil e importante que proporciona consultas, tipos, restricciones e indexación. Pero por debajo, es clave-valor hasta el fondo.

El círculo completo de mi carrera:

EraBase de DatosAlmacenamientoAccesoEsquema
1997MSM/MUMPSB-tree globalsClave directaConvención
2006CachéB-tree globals + SQLClave o SQLConvención + proyectado
2015SQL Server (EAV)Páginas B-treeSQL sobre clave-valorCódigo de aplicación
2018.NET/SQL ServerPáginas B-treeSQL (normalizado)DDL explícito
2024D1/SQLitePáginas B-treeSQL en edgeDDL explícito

Todas son un B-tree almacenando pares clave-valor. La diferencia es la capa de ceremonia — cuánta estructura impone el sistema entre tu intención y los bits en disco.

Lo Que 25 Años de Clave-Valor Me Enseñaron

1. Toda migración es un proyecto de descubrimiento de esquema

Ya estés migrando globals MUMPS, tablas EAV o una colección MongoDB a PostgreSQL, la parte más difícil nunca es la transferencia de datos. Es entender el esquema implícito — las reglas codificadas en la lógica de aplicación que restringen cómo realmente se ven los datos, a diferencia de lo que la base de datos permite que se vean. Presupuesta el 60% del tiempo de migración para arqueología de esquemas.

2. Las transiciones de acceso dual son el único camino seguro

Toda migración exitosa que he hecho mantuvo los patrones de acceso antiguos y nuevos simultáneamente. Caché dejaba coexistir globals y SQL. Mi migración en Werfen usó vistas SQL sobre EAV. El motor CDC de MUMPS→SQL mantenía ambos sistemas vivos. Nunca cortes de un paso. El riesgo no son los datos — son los patrones de acceso que no sabías que existían.

3. Modelo de almacenamiento ≠ modelo de datos

Los globals MUMPS podían almacenar datos relacionales. SQL Server con EAV almacenaba datos documentales. SQLite almacena todo como pares clave-valor por debajo. El modelo de almacenamiento es un detalle de implementación. Lo que importa es el modelo de datos — la estructura lógica de tu dominio — y si tus patrones de acceso están alineados con él.

4. La flexibilidad de esquema es un espectro, no un binario

Globals MUMPS: máxima flexibilidad, cero enforcement. SQL con constraints: mínima flexibilidad, máximo enforcement. EAV: en algún punto intermedio (valores sin esquema, pero estructura SQL alrededor). Los sistemas modernos como D1 con columnas JSON ocupan aún otro punto de este espectro. Elige el nivel de flexibilidad que coincida con la disciplina de tu equipo. Más flexibilidad exige más disciplina de código.

5. La mejor base de datos es la que entiendes completamente

Los programadores MUMPS que entendían los globals a fondo construyeron sistemas que funcionaron 30 años. Los expertos SQL que entienden los planes de consulta evitan las trampas de rendimiento que atrapan a todos los demás. He visto equipos adoptar MongoDB, PostgreSQL o DynamoDB no porque entendieran los trade-offs, sino porque era popular. Luego pasaron años peleando con la base de datos en lugar de usarla.

Mi recomendación: empieza con SQLite. Es la expresión más pura de "clave-valor + ceremonia SQL" disponible hoy. Con D1, corre en el edge. No tiene configuración. Sin connection pooling. Sin gestión de cluster. Te fuerza a entender los fundamentales — B-trees, índices, planes de consulta — sin la complejidad de los sistemas distribuidos. Cuando lo superes (y puede que no — SQLite aguanta más de lo que la gente cree), sabrás exactamente por qué necesitas algo más complejo.

6. El círculo siempre se cierra

En 1997, almacenaba datos de pacientes como pares clave-valor jerárquicos en globals MUMPS. En 2024, almaceno estado de aplicación como pares clave-valor en páginas B-tree de D1, accedidos vía SQL. Los paradigmas cambian — relacional, documental, grafo, series temporales — pero la operación fundamental permanece: almacena un valor en una clave, recupéralo después, hazlo rápido. Si entiendes esta primitiva profundamente, cada nueva tecnología de base de datos se convierte en una variación de un tema que ya conoces.

Los ingenieros que tienen problemas con las migraciones de bases de datos son invariablemente los que aprendieron un producto de base de datos específico en lugar de aprender primitivas de almacenamiento de datos. Aprende cómo funcionan los B-trees. Aprende cómo los write-ahead logs proporcionan durabilidad. Aprende cómo los índices intercambian rendimiento de escritura por rendimiento de lectura. Entonces cada base de datos — desde globals MUMPS hasta Cloudflare D1 — se convierte en un instrumento familiar tocando una melodía diferente.

Etiquetas

Migración de Bases de Datos Clave-Valor MUMPS Caché SQLite EAV Arquitectura de Datos

Sobre el Autor

Gonzalo Monzón

Gonzalo Monzón

Fundador & Arquitecto Principal

Gonzalo Monzón es Arquitecto de Soluciones Senior e Ingeniero IA con más de 26 años construyendo sistemas críticos en Sanidad, Automatización Industrial e IA empresarial. Fundador de Cadences Lab, está especializado en conectar infraestructura legacy con tecnología de vanguardia.

Mantente al día

Recibe notificaciones cuando publiquemos nuevos artículos sobre automatización IA, casos de uso y guías prácticas.

Artículos Relacionados

Ingeniería
11 min lectura

Edge Computing: Por Qué lo Apostamos Todo a Cloudflare (Y Qué Consigues por $65/Mes)

Sin servidores, sin contenedores, sin Kubernetes. Corremos 14+ productos interconectados en 9 productos Cloudflare — Workers, D1, R2, Durable Objects, Pages, KV, Vectorize, Workers AI y WAF. $65/mes por lo que costaría $400-600 en AWS. La arquitectura completa.

GM
25 de agosto de 2025
Leer Artículo →
Ingeniería
9 min lectura

SQLite Es la Base de Datos de Producción Que Ya Conoces (Solo Que Aún No Lo Sabes)

DHH alcanzó 30.000 escritores concurrentes en SQLite. Nosotros ejecutamos 14+ productos en Cloudflare D1 (SQLite en el edge) por 5$/mes. SQLite no es la base de datos de juguete que crees — está impulsando todo, desde ONCE de 37signals hasta toda nuestra plataforma multi-tenant. Así es como la industria está convergiendo en la base de datos más desplegada del mundo.

GM
5 de marzo de 2026
Leer Artículo →
Ingeniería
10 min lectura

Vanilla JS Es el Lenguaje Ensamblador del Navegador (Y Por Eso Lo Usamos)

Gmail envía 20MB de JavaScript. Slack 55MB. Nuestro sistema de cookie consent? 4KB, cero dependencias. Cuando entiendes las primitivas de bajo nivel — vanilla JS, CSS puro, APIs nativas del DOM — no necesitas un framework que te diga lo que el navegador ya sabe. Pero no somos anti-frameworks: usamos Astro para SSG y React islands donde realmente ayudan. La diferencia es que elegimos nuestras herramientas — no nos eligen a nosotros.

GM
13 de marzo de 2026
Leer Artículo →