Modelización de datos: cuándo integrar, cuándo remitir

Una de las grandes cuestiones que se plantean en el modelado de bases de datos documentales es: ¿hasta dónde puedo llegar con la desnormalización?

Cuando trabajamos con bases de datos relacionales, estamos acostumbrados a normalizar estrictamente nuestros datos: tenemos una instancia canónica, no duplicada, de cada dato. Eso nos da un margen casi ilimitado de consulta y hace que la coherencia sea pan comido.

En mi anterior post sobre modelización de datosHemos visto que las bases de datos de documentos adoptan un enfoque diferente. Las bases de datos de documentos optimizan el almacenamiento conjunto de los datos a los que accedemos juntos y, de ahí, se derivan otras muchas ventajas, como la velocidad, la distribuibilidad, la conservación de la estructura de los documentos, etc.

En ese post puse el ejemplo de un sistema de gestión de botines en el que un pedido se almacenaría como un documento JSON, en lugar de dividirse en varias tablas y luego reconstruirse cada vez mediante una consulta SQL.

Ese modelo -de almacenamiento de agregados de datos- se desnormaliza de forma natural. Sin embargo, eso no significa que debamos crear documentos monolíticos para cada contexto.

En su lugar, debemos considerar dos opciones: podemos incrustar datos de varios lugares en un documento o podemos almacenar referencias a otros documentos.

Acceso a documentos clave-valor

Con Couchbase tenemos un par de formas de acceder a nuestros datos: consultas de valores clave y vistas (índices secundarios generados automáticamente a partir de consultas map-reduce).

En N1QL esté disponible, serán tres.

Todo lo que vamos a ver en este post se basa en búsquedas clave-valor.

Un breve resumen de nuestro sistema de ejemplo

En mi entrada anterior vimos el ejemplo de un sistema de gestión de existencias para hacer un seguimiento del botín de marca de Couchbase.

Imaginemos que la ruta estándar es:

  1. Un cliente hace un pedido.
  2. Un preparador de pedidos recibe el pedido y empaqueta los artículos.
  3. Un expedidor envía el paquete a través de un servicio de reparto.

En el momento en que el cliente realiza un pedido, podemos elegir cómo almacenar los datos del pedido en Couchbase:

  • incluir toda la información del pedido en un documento
  • o mantener una copia principal de cada registro implicado y hacer referencia a él desde el documento de pedido.

Inserción

Si elegimos incrustar todos los datos en un documento, podríamos acabar con algo como esto:

  {
"orderID": 200,
"cliente":
{
"Nombre": "Steve Rothery",
"address": "11-21 Paul Street",
"ciudad": "Londres"
},
"productos":
[
{
"itemCode": "RedTShirt",
"itemName": "Camiseta roja Couchbase",
"proveedor": "empresa de camisetas",
"localización": "almacén 1, pasillo 3, ubicación 4",
"quantityOrdered": 3
},
{
"itemCode": "USB",
"proveedor": "Memorysticks Foreva",
"itemName": "Memoria USB negra de 8 GB con el logotipo rojo de Couchbase",
"localización": "almacén 1, pasillo 42, ubicación 12",
"quantityOrder": 51
}
],
"status": "pagado"
}

Aquí, todo lo que necesitamos para cumplir el pedido se almacena en un solo documento.

A pesar de tener documentos separados con el perfil del cliente y los detalles del artículo, replicamos parte de sus datos en el documento del pedido.

Esto puede parecer un despilfarro o incluso peligroso, si vienes del mundo relacional.

Sin embargo, es bastante normal para una base de datos de documentos. Como hemos visto antes, las bases de datos de documentos funcionan en torno a la idea de que un documento puede almacenar todo lo que necesitas para una situación concreta.

Sin embargo, incrustar datos de este modo tiene algunas desventajas.

En primer lugar, veamos lo que es potencialmente malo:

  • Incoherencia: si Steve quiere actualizar su dirección después de hacer el pedido, nos basamos en:
    • que el código de nuestra aplicación sea lo suficientemente robusto como para encontrar cada instancia de su dirección en la base de datos y actualizarla.
    • nada va mal en la red, en la base de datos o en cualquier otro lugar que impida que la actualización se complete por completo.
  • Consultabilidad: al hacer varias copias de los mismos datos, podría ser más difícil consultar los datos que replicamos, ya que tendremos que filtrar todas las copias incrustadas.
  • Tamaño: puedes acabar teniendo documentos de gran tamaño compuestos por muchos datos duplicados.
  • Más documentos: no es un problema importante, pero podría tener algunas repercusiones, como el tamaño de tu conjunto de trabajo en caché.

Entonces, ¿qué beneficios nos aporta la incrustación? Principalmente, nos da:

  • Rapidez de acceso: incrustar todo en un documento significa que sólo necesitamos una consulta de la base de datos.
  • Mayor tolerancia a fallos en el momento de la lectura: en una base de datos distribuida, los documentos a los que nos referimos estarían en varias máquinas, por lo que al incrustarlos estamos introduciendo menos oportunidades de que algo vaya mal y estamos simplificando el lado de la aplicación.

Cuándo incrustar

Es posible que desee incrustar datos cuando:

  1. Las lecturas superan ampliamente a las escrituras.
  2. Te sientes cómodo con el escaso riesgo de que los datos sean incoherentes en las múltiples copias.
  3. Estás optimizando la velocidad de acceso.

¿Por qué nos preguntamos si el número de lecturas supera al de escrituras?

En nuestro ejemplo anterior, cada vez que alguien lee nuestro pedido también es probable que actualice el estado del pedido:

  • alguien en el almacén lee el documento de pedido y actualiza el estado a "Recogido", una vez que ha terminado
  • un miembro de nuestro equipo de envíos lee el documento y actualiza el estado a "Enviado" cuando el paquete está en manos del transportista
  • cuando recibimos un aviso de entrega automático del servicio de mensajería, nuestra aplicación actualiza el estado del documento a "Entregado".

Por lo tanto, aquí las lecturas y las escrituras suelen estar bastante equilibradas.

Imaginemos, sin embargo, que añadimos un blog a nuestro sistema de gestión de botines y escribimos un post sobre nuestro nuevo cargador USB con la marca Couchbase. Haríamos dos, quizá tres, escrituras en el documento mientras afinamos nuestro post. Después, durante el resto de la vida del documento, todo serían lecturas. Si el post es popular, podríamos ver cien o mil veces más lecturas que escrituras.

Como las ventajas de la incrustación se producen en el momento de la lectura, y los riesgos sobre todo en el momento de la escritura, parece razonable incrustar todo el contenido de la página de la entrada del blog en un documento en lugar de, por ejemplo, extraer los detalles del autor de un documento de perfil separado.

Hay otra razón de peso para integrar datos:

  • En realidad, lo que quieres es mantener copias de datos separadas y divergentes.

En nuestro pedido de swag, utilizamos la dirección del cliente como dirección de envío. Al incrustar la dirección de envío, podemos ofrecer fácilmente la opción de elegir una dirección de envío diferente para cada pedido. También obtenemos un registro histórico del destino de cada pedido, incluso si el cliente cambia posteriormente la dirección almacenada en su perfil.

Necesidad de velocidad

Couchbase es rápido.

Todas las escrituras se realizan en la caché gestionada y, si dimensionamos nuestra RAM adecuadamente, nuestro conjunto de trabajo se sirve desde esa caché.

Eso cambia la ponderación de las compensaciones que hacemos. Incrustar principalmente por velocidad es menos convincente con Couchbase.

Con Couchbase el tiempo medio de una operación de lectura/escritura es de medio milisegundo, así que no pasa nada cuando una sola consulta requiere tres o cuatro operaciones.

Remitir a

Otra forma de representar nuestro pedido sería hacer referencia al documento de perfil de usuario y al documento de detalles de artículos de stock, pero sin extraer su contenido en el documento de pedido.

Imaginemos que los perfiles de nuestros clientes están codificados por su dirección de correo electrónico y los artículos de nuestras existencias por un código de existencias. Podemos utilizarlos para referirnos a los documentos originales:

   {
"orderID": 200,
"cliente": "steve@gmail.com",
"productos":
[
{
"itemCode": "RedTShirt",
"quantityOrdered": 3
},
{
"itemCode": "USB",
"quantityOrder": 51
}
],
"status": "pagado"
}

Cuando vemos el pedido de Steve, podemos completar los detalles con tres lecturas más: su perfil de usuario (introducido por la dirección de correo electrónico) y los detalles de los artículos en stock (introducidos por sus códigos de artículo).

Requiere tres lecturas adicionales, pero nos aporta algunas ventajas:

  • Coherencia: mantenemos una copia canónica de la información del perfil de Steve y de los detalles de los artículos en stock.
  • Consultabilidad: esta vez, cuando consultamos el conjunto de datos podemos estar más seguros de que los resultados son las versiones canónicas de los datos y no copias incrustadas.
  • Mejor uso de la caché: dado que accedemos con frecuencia a los documentos canónicos, éstos permanecerán en nuestra caché, en lugar de tener múltiples copias incrustadas a las que se accede con menos frecuencia y que, por tanto, desaparecen de la caché.
  • Uso más eficiente del hardware: al incrustar los datos obtenemos documentos más grandes con varias copias de los mismos datos, lo que ayuda a reducir el disco y la RAM que necesita nuestra base de datos.

También hay desventajas:

  • Múltiples búsquedas: esto se tiene en cuenta sobre todo en el caso de las pérdidas de caché, ya que el tiempo de lectura aumenta cada vez que tenemos que leer del disco.
  • Se impone la coherencia: hacer referencia a una versión canónica de un documento significa que las actualizaciones de ese documento se reflejarán en todos los contextos en los que se utilice.

Cuándo remitir

Referirse a instancias canónicas de documentos es una buena opción por defecto cuando se modela con Couchbase. Deberías estar especialmente interesado en usar referencias cuando:

  • La coherencia de los datos es una prioridad.
  • Usted quiere asegurarse de que su caché se utiliza de manera eficiente.
  • La versión incrustada sería poco manejable.

Este último punto es especialmente importante cuando sus documentos tienen un potencial de crecimiento ilimitado.

Imaginemos que almacenamos los registros de actividad de cada usuario de nuestro sistema. Integrar esos registros en el perfil del usuario podría dar lugar a un documento bastante voluminoso.

Es poco probable que superemos el límite máximo de 20 MB de Couchbase para un documento individual, pero procesar el documento en el lado de la aplicación sería menos eficiente a medida que creciera el elemento de registro del perfil. Sería mucho más eficiente hacer referencia a un documento separado, o tal vez a documentos paginados, que contengan los registros.

Desnormalizar todas las cosas (Excepto cuando no lo haces)

La desnormalización es una parte clave del trabajo con bases de datos de documentos, pero eso no significa que no podamos mantener registros canónicos y luego referirnos a ellos desde dentro de otros documentos.

De hecho, referirse a los documentos es a menudo la forma más eficiente de trabajar con Couchbase y debemos incrustar en situaciones particulares, tales como cargas de trabajo de lectura pesada.

La próxima vez me ocuparé de los patrones de nomenclatura de las claves y de cómo mantenemos el esquema en una base de datos de esquema suave.

Comparte este artículo
Recibe actualizaciones del blog de Couchbase en tu bandeja de entrada
Este campo es obligatorio.

Autor

Publicado por Matthew Revell, Defensor principal del desarrollador, EMEA, Couchbase

Matthew Revell es Lead Dev Advocate, EMEA Couchbase. Ha desarrollado una estrategia global para situar a Couchbase en la mente de los desarrolladores del producto.

2 Comentarios

  1. ¿no entiendo por qué lo siguiente es una desventaja o un problema en general?

    Se impone la coherencia: hacer referencia a una versión canónica de un documento significa que las actualizaciones de ese documento se reflejarán en todos los contextos en los que se utilice.

Deja un comentario

¿Listo para empezar con Couchbase Capella?

Empezar a construir

Consulte nuestro portal para desarrolladores para explorar NoSQL, buscar recursos y empezar con tutoriales.

Utilizar Capella gratis

Ponte manos a la obra con Couchbase en unos pocos clics. Capella DBaaS es la forma más fácil y rápida de empezar.

Póngase en contacto

¿Quieres saber más sobre las ofertas de Couchbase? Permítanos ayudarle.