Atlasingeniería

Bases de datosMotor y ejecuciónTema 4

NoSQL: cuándo conviene y cuándo no

No es una tecnología sino cuatro familias distintas, unidas por resignar algo del modelo relacional a cambio de otra cosa. La pregunta útil no es cuál es mejor, sino qué se está resignando.

Para este tema conviene tener claro:Formas normales y por qué importanÍndices: estructura interna y costo

“NoSQL” agrupa bases que no se parecen entre sí: un almacén clave-valor y una base de grafos tienen tan poco en común como cualquiera de los dos con PostgreSQL. Lo único que comparten es haber resignado algo de lo relacional, y conviene saber qué antes de elegir.

Las cuatro familias

Son cuatro familias. Clave-valor —Redis, DynamoDB— guarda un blob por clave y sólo responde por esa clave: rapidísimo y sin consultas por contenido. Documentos —MongoDB— guarda estructuras anidadas tipo JSON y permite consultar por sus campos.

Columnares anchas —Cassandra, HBase— están pensadas para escrituras masivas distribuidas y consultas por rango de clave. Grafos —Neo4j— hacen eficiente recorrer relaciones, que es justamente lo que más cuesta en el modelo relacional.

Antes de seguir, predecí

Un documento guarda el pedido con los datos del cliente adentro. El cliente cambia de dirección. ¿Qué hay que hacer?

Qué se resigna a cambio

Lo que se resigna casi siempre es alguna combinación de tres cosas: las consultas ad hoc con joins, las garantías transaccionales sobre varias entidades, y el esquema declarado.

Esa última merece una aclaración. “Sin esquema” no significa que no haya esquema: significa que el esquema está en el código de la aplicación en vez de en la base, y que conviven varias versiones de él en los mismos datos. Eso es cómodo al principio y es deuda pura a los dos años.

Relacional: el pedido, sus ítems y el producto viven en tablas separadas, cada dato una sola vez.

1 / 5
Los mismos datos, dos formas. La de arriba hace barato cambiar el precio de un producto en un solo lugar; la de abajo hace barato traer un pedido entero en una lectura. Ninguna es mejor: la pregunta es cuál de las dos operaciones hacés mil veces por segundo.

CAP, que se cita mucho y se entiende mal

El teorema CAP se cita mucho y se entiende mal. Dice que un sistema distribuido, cuando hay una partición de red, tiene que elegir entre seguir respondiendo con datos posiblemente viejos o rechazar operaciones para no perder consistencia.

No dice que haya que elegir dos de tres en condiciones normales. Y como las particiones son inevitables en una red real, la elección real es entre disponibilidad y consistencia durante la falla. PACELC agrega la otra mitad: incluso sin partición hay que elegir entre latencia y consistencia.

La consistencia eventual y cuándo alcanza

De ahí sale la consistencia eventual: las réplicas convergen, pero durante un rato pueden devolver valores distintos. Para un contador de vistas es aceptable; para el saldo de una cuenta, no.

La consecuencia práctica es que la aplicación tiene que manejar casos que con una base transaccional no existen: leer lo que uno mismo acaba de escribir y no verlo, o resolver dos escrituras concurrentes que quedaron en conflicto. Ese trabajo no desaparece, se mueve al código.

Dónde la elección es clara

Hay casos donde la elección es clara. Caché y sesiones: clave-valor. Series temporales y telemetría con volumen alto de escritura: columnar. Recorridos de relaciones a profundidad variable —quién conoce a quién, rutas, permisos heredados—: grafos, porque en SQL eso son joins recursivos caros.

Documentos conviene cuando la unidad natural de lectura y escritura es un agregado completo que siempre se accede entero y no se cruza con otros.

La razón que no alcanza

Y hay una razón que no alcanza: “no quiero definir el esquema”. Eso posterga una decisión que hay que tomar igual, y la paga quien tenga que consultar datos escritos por tres versiones distintas de la aplicación.

Tampoco alcanza “necesito escalar”, al menos no antes de medir. Una base relacional en un servidor razonable maneja volúmenes mucho mayores de lo que la intuición sugiere, y los motores actuales tienen tipos JSON con índices: se puede guardar un documento en una columna y conservar transacciones, joins y restricciones para el resto. Muchas veces ésa es la respuesta correcta, y no hace falta elegir bando.

La pregunta no es cuál es mejor

Si tu problema es...ConvienePor qué
consultas variadas que no se pueden preverrelacionalSQL responde preguntas que nadie anticipó
leer siempre el mismo documento enterodocumentosuna lectura en vez de un join
escrituras masivas por clave y rangocolumnar anchaestá diseñada para eso
recorrer relaciones de varios saltosgrafosel join recursivo es carísimo en relacional
una caché o una colaclave-valorno hace falta consultar por contenido
La primera fila es la que más se subestima al empezar un proyecto: al principio no se sabe qué se va a preguntar, y ahí el relacional gana por no obligar a decidirlo.
Más a fondo · nivel seniorCAP se cita mal casi siempre

El teorema dice que ante una partición de red, un sistema distribuido tiene que elegir entre seguir respondiendo con datos posiblemente viejos o dejar de responder. Eso es todo.

Los dos malentendidos frecuentes: no dice que haya que elegir dos de tres como si fuera un menú —la partición no se elige, ocurre—, y no dice nada sobre el comportamiento cuando la red anda bien, que es el 99,9 % del tiempo. Para ese caso normal la formulación útil es PACELC: si hay partición, elegir entre disponibilidad y consistencia; si no, elegir entre latencia y consistencia.

Esa segunda parte es la que aparece todos los días: una réplica de lectura responde más rápido y puede estar unos milisegundos atrasada, y decidir si eso es aceptable para cada consulta es una decisión de producto. Leer el saldo de una cuenta, no; el catálogo, sí.

Cierre

NoSQL son cuatro familias con problemas distintos, unidas por resignar joins, transacciones o esquema. CAP obliga a elegir sólo durante la partición, y la consistencia eventual mueve trabajo a la aplicación. La pregunta es qué se resigna, y muchas veces la respuesta es una columna JSON en la base relacional que ya está.

Autoevaluación

¿Lo entendiste?

¿Qué tienen en común las bases NoSQL?
«Sin esquema», ¿qué significa realmente?
¿Qué dice exactamente el teorema CAP?
¿Para qué sirve específicamente una base de grafos?