sql >> Base de Datos >  >> NoSQL >> MongoDB

Seguidores - diseño de base de datos mongodb

Estoy de acuerdo con la noción general de otras respuestas de que este es un límite problema relacional.

La clave de los modelos de datos de MongoDB es la escritura pesada, pero eso puede ser complicado para este caso de uso, principalmente debido a la contabilidad que se requeriría si quisiera vincular usuarios a elementos directamente (un cambio a un grupo seguido de muchos de los usuarios incurriría en una gran cantidad de escrituras, y necesita algún trabajador para hacer esto).

Investiguemos si el modelo de lectura intensiva no es aplicable aquí o si estamos haciendo una optimización prematura.

El enfoque de lectura intensiva

Su principal preocupación es el siguiente caso de uso:

un problema real de rendimiento podría ser cuando quiero obtener todos los grupos que sigue un usuario para un elemento específico [...] porque luego tengo que encontrar todos los grupos que sigue el usuario y, a partir de ahí, encontrar todos los item_groups con el group_id $in y la identificación del artículo.

Analicemos esto:

  • Obtener todos los grupos que sigue el usuario

    Esa es una consulta simple:db.followers.find({userId : userId}) . Vamos a necesitar un índice en userId lo que hará que el tiempo de ejecución de esta operación sea O(log n), o ultrarrápido incluso para n grande.

  • a partir de ahí, encuentre todos los grupos de elementos con el ID de grupo $in y la identificación del artículo

    Ahora bien, esta es la parte más complicada. Supongamos por un momento que es poco probable que los elementos formen parte de una gran cantidad de grupos. Luego un índice compuesto { itemId, groupId } funcionaría mejor, porque podemos reducir drásticamente el conjunto de candidatos a través del primer criterio:si un elemento se comparte en solo 800 grupos y el usuario sigue 220 grupos, mongodb solo necesita encontrar la intersección de estos, lo cual es comparativamente fácil porque ambos los conjuntos son pequeños.

Sin embargo, tendremos que profundizar más que esto:

La estructura de sus datos es probablemente el de una red compleja . Las redes complejas vienen en muchos sabores, pero tiene sentido asumir que su gráfico de seguidores está casi libre de escala, que también es prácticamente el peor de los casos. En una red libre de escala, una cantidad muy pequeña de nodos (celebridades, super bowl, Wikipedia) atraen mucha 'atención' (es decir, tienen muchas conexiones), mientras que una cantidad mucho mayor de nodos tiene problemas para obtener la misma cantidad de atención. combinado .

Los pequeños nódulos no son motivo de preocupación , las consultas anteriores, incluidos los viajes de ida y vuelta a la base de datos, están en el rango de 2 ms en mi máquina de desarrollo en un conjunto de datos con decenas de millones de conexiones y> 5 GB de datos. Ahora que el conjunto de datos no es enorme, pero no importa qué tecnología elija, estará vinculado a la RAM porque los índices deben estar en la RAM en cualquier caso (la localidad de los datos y la separabilidad en las redes son generalmente deficientes), y el tamaño de intersección establecido es pequeño por definición. En otras palabras:este régimen está dominado por cuellos de botella de hardware.

¿Qué pasa con los supernodos? aunque?

Dado que eso sería una conjetura y estoy muy interesado en los modelos de red, me tomé la libertad de implementar una herramienta de red dramáticamente simplificada basada en su modelo de datos para realizar algunas mediciones. (Lo siento, está en C#, pero generar redes bien estructuradas ya es bastante difícil en el idioma que domino con mayor fluidez...).

Al consultar los supernodos, obtengo resultados en el rango de 7 ms como máximo (eso es en 12 millones de entradas en una base de datos de 1,3 GB, con el grupo más grande con 133 000 elementos y un usuario que sigue 143 grupos).

La suposición en este código es que la cantidad de grupos seguidos por un usuario no es enorme, pero parece razonable aquí. Si no es así, optaría por el enfoque de escritura intensa.

Siéntete libre de jugar con el código. Desafortunadamente, necesitará un poco de optimización si desea probar esto con más de un par de GB de datos, porque simplemente no está optimizado y hace algunos cálculos muy ineficientes aquí y allá (especialmente la reproducción aleatoria ponderada beta podría mejorarse ).

En otras palabras:no me preocuparía el rendimiento del enfoque de lectura intensiva todavía . El problema a menudo no es tanto que la cantidad de usuarios crezca, sino que los usuarios usan el sistema de formas inesperadas.

El enfoque de escritura intensa

El enfoque alternativo es probablemente invertir el orden de vinculación:

UserItemLinker
{
 userId,
 itemId,
 groupIds[]  // for faster retrieval of the linker. It's unlikely that this grows large
}

Este es probablemente el modelo de datos más escalable, pero no lo elegiría a menos que estemos hablando de ENORMES cantidades de datos donde la fragmentación es un requisito clave. La diferencia clave aquí es que ahora podemos compartimentar de manera eficiente los datos usando el ID de usuario como parte de la clave de partición. Eso ayuda a paralelizar consultas, fragmentar de manera eficiente y mejorar la ubicación de los datos en escenarios de varios centros de datos.

Esto podría probarse con una versión más elaborada del banco de pruebas, pero aún no encontré el tiempo y, francamente, creo que es excesivo para la mayoría de las aplicaciones.