¿Cuándo se rompe tanto el modelo relacional que conviene recurrir a una base de datos de grafos?
Los joins relacionales se vuelven más lentos mientras más profunda es una relación; las bases de datos de grafos guardan la relación misma como un puntero indexado de primera clase, así que recorrer cinco saltos cuesta casi lo mismo que recorrer uno.
APRENDE HACIENDOPon a prueba tu intuición3 pasos
¿Cuándo se rompe tanto el modelo relacional que conviene recurrir a una base de datos de grafos?
Usa los ejemplos y la explicación de la lección para comprobar tu idea.
Reflexión personal. No se envía a ningún servicio de IA.#Relaciones como dato, no como joins
Cualquier base de datos relacional puede modelar relaciones: para eso existen las claves foráneas y las tablas intermedias. Lo que no puede hacer barato es recorrer una relación cuya profundidad no conoces de antemano. "Encuentra a mis amigos" es un join. "Encuentra a personas conectadas conmigo a través de amigos en común" son dos. "Encuentra a todos los alcanzables desde mí a través de esta red, sin importar cuántos saltos tome" es una consulta recursiva que un motor relacional tiene que resolver join por join, nivel por nivel, y cuyo costo crece con cuánto de la tabla tiene que tocar en cada nivel.
Una base de datos de grafos invierte ese modelo de costos. Los nodos y las relaciones se guardan de forma que cada nodo conoce físicamente sus propias relaciones adyacentes, una técnica que se suele llamar adyacencia libre de índice (index-free adjacency). Recorrer de un nodo a sus vecinos es un salto de puntero, no una búsqueda en un índice sobre una tabla potencialmente enorme, así que el costo de un recorrido es proporcional al tamaño del vecindario que realmente visitas, no al tamaño de todo el conjunto de datos. Un recorrido de cinco saltos sobre un grafo con 50 millones de nodos puede costar más o menos lo mismo que un recorrido de cinco saltos sobre un grafo de 500, porque el tamaño total del grafo nunca se consulta para las partes que no tocas.
#Dónde el modelo relacional realmente se rompe
- La profundidad es variable o desconocida de antemano. "¿Cómo está conectada la Persona A con la Persona B?" (cualquier número de saltos), "¿qué permisos hereda este usuario de forma transitiva por pertenecer a grupos?", "¿qué se rompe si retiro este microservicio, considerando a los que llaman a quienes lo llaman?": son preguntas de búsqueda de caminos, y encontrar caminos es justo para lo que está construido un motor de grafos.
- Las relaciones son el dato interesante, no las entidades. Los anillos de fraude son el caso de libro: individualmente, diez cuentas se ven normales. Lo que las convierte en un anillo es que comparten un dispositivo, un método de pago y una dirección en un patrón entrelazado: el grafo de conexiones es la señal, no ninguna fila por sí sola.
- Aparecen tipos de relación nuevos con frecuencia. Agregar "Persona MENTORA A Persona" a un grafo es un tipo de relación nuevo; agregarlo a un esquema relacional es una tabla intermedia nueva, claves foráneas nuevas y una migración, por cada tipo nuevo de conexión que le sale a tu producto.
- Las consultas de recomendación y similitud recorren conexiones compartidas. "Los clientes que compraron lo que compraste también compraron…" es, por debajo, un recorrido de varios saltos (tú → compra → producto → otros compradores → sus otras compras) que una consulta de grafo expresa directamente y que SQL expresa a través de varios joins que empeoran cada vez que agregas un salto.
#Una comparación concreta
Aquí está "sugerir personas que quizás conozcas" —amigos de amigos que todavía no son tus amigos— primero como tendrías que escribirlo contra un esquema relacional con una CTE recursiva:
WITH RECURSIVE red(person_id, profundidad) AS (SELECT friend_id, 1FROM friendshipsWHERE person_id = 4471UNION ALLSELECT f.friend_id, r.profundidad + 1FROM friendships fJOIN red r ON f.person_id = r.person_idWHERE r.profundidad < 2)SELECT DISTINCT person_idFROM redWHERE profundidad = 2AND person_id NOT IN (SELECT friend_id FROM friendships WHERE person_id = 4471);
Eso ya es incómodo con dos saltos, y cada salto adicional significa otro paso recursivo más una deduplicación más cuidadosa. Aquí está la misma pregunta en Cypher, contra una base de datos de grafos nativa:
MATCH (yo:Person {id: 4471})-[:FRIENDS_WITH]->(:Person)-[:FRIENDS_WITH]->(sugerencia:Person)WHERE sugerencia <> yoAND NOT (yo)-[:FRIENDS_WITH]->(sugerencia)RETURN sugerencia.name AS sugerencia, count(*) AS amigosEnComunORDER BY amigosEnComun DESCLIMIT 10;
Ampliar esto de "amigos de amigos" a "cualquiera alcanzable en 4 saltos" es un cambio de un carácter (*1..4 en la relación) en Cypher; en SQL implica reescribir la profundidad de la recursión y volver a verificar que la lógica de deduplicación siga siendo válida.
MATCH (yo:Person {id: 4471})-[:FRIENDS_WITH*1..4]-(alcanzable:Person)RETURN DISTINCT alcanzable.name;
En el diagrama de arriba, Cara y Eli están a dos y tres saltos de "Yo" respectivamente: un motor de grafos encuentra a ambos recorriendo punteros físicos de relación hacia afuera; un motor relacional los encuentra volviendo a hacer join sobre la tabla de amistades una vez por cada salto.
#Dónde una base de datos de grafos es la herramienta equivocada
- La agregación masiva sobre conjuntos planos y grandes —"ingresos totales por región el trimestre pasado"— sigue siendo normalmente más rápida y simple en un almacén relacional o columnar; los motores de grafos están optimizados para recorrer, no para escanear y sumar millones de filas.
- La analítica de grafo completo (centralidad estilo PageRank, detección de comunidades sobre todo el grafo) suele necesitar un motor de procesamiento de grafos por lotes dedicado, en vez de una base de datos de grafos OLTP afinada para recorridos individuales rápidos.
- Relaciones superficiales y bien conocidas —un usuario tiene muchos pedidos, un pedido tiene muchas líneas— no necesitan una base de datos de grafos en absoluto. Una clave foránea y un join indexado ya responden eso en tiempo efectivamente constante; recurrir a Neo4j o similar aquí agrega un lenguaje de consulta poco familiar y una segunda base de datos que operar, sin ningún beneficio de recorrido que realmente estés aprovechando.