A medida que las bases de datos NoSQL evolucionaban, cada una añadía API o lenguajes de más alto nivel para ayudar a los programadores a realizar cosas complejas con facilidad. SQL, después de haber hecho eso para los datos relacionales, mostró el camino. En SQL, los programadores dicen QUÉ hay que hacer y el motor de la base de datos resuelve el CÓMO. El CÓMO es el procedimiento/algoritmo eficiente para ejecutar la sentencia. Seleccionar, unir y proyectar son las operaciones básicas del procesamiento SQL. Incluso en los sistemas NoSQL, cuando se modelan los datos sin mucha normalización, sigue siendo necesario unir una colección de objetos. Clientes con pedidos, pedidos con inventario, inventario con proveedores, proveedores con créditos y así sucesivamente. Por lo tanto, Couchbase N1QL ha soportado operaciones de unión desde su primera versión. Después de eso, MongoDB, en la versión 3.2, añadió el operador $lookup al marco de agregación para realizar las operaciones de unión.

Sin una función de consulta expresiva y de alto rendimiento, los desarrolladores de aplicaciones tienen que hacerlo dentro de la aplicación o exportar los datos a un sistema que lo haga. Ambas propuestas son caras.

En este artículo, vamos a comparar Couchbase vs. MongoDB y sus diferentes enfoques para unir documentos JSON. Específicamente, haremos un estudio comparativo del uso de joins para colecciones de MongoDB frente a cómo podemos ejecutarlos en Couchbase. Cassandra CQL y DynamoDB no admiten uniones de forma nativa. Los desarrolladores deben hacer el trabajo ellos mismos o utilizar otras capas como Spark o Amazon EMR para lograr el mismo resultado. Por lo tanto, no las trataremos en este artículo..

Uniones en Couchbase

Couchbase introdujo las uniones INNER y LEFT OUTER a partir de Couchbase 4.0 (2015). Esto soporta uniones de una relación hijo a padre. Los documentos hijos (por ejemplo, pedidos) se pueden unir con los documentos padres (por ejemplo, clientes). En 4.5 (2016), Couchbase introdujo uniones de índices para consultar uniones de padre a hijo. En ambos casos, existía un predicado implícito de igualdad entre atributo-valor y clave de documento, especificado por la cláusula ON KEY.  

Couchbase 5.5 tiene el estándar ANSI SQL extendido para JSON. Soporta INNER JOIN, LEFT OUTER JOIN y RIGHT OUTER join limitado. Usaremos ejemplos basados en Couchbase 5.5.

Couchbase se une a la documentación: https://developer.couchbase.com/documentation/server/5.5/n1ql/n1ql-language-reference/from.html

Uniones y colecciones de MongoDB:

Las uniones se realizan mediante el operador $lookup dentro del marco de agregación.

A continuación se presentan extractos de la documentación de MongoDB.

Nuevo en la versión 3.2.

Realiza una unión externa izquierda con una colección no separada en la tabla mismo para filtrar los documentos de la colección "unida" para su procesamiento. Para cada documento de entrada, el 1TP4Búsqueda añade un nuevo campo de matriz cuyos elementos son los documentos coincidentes de la colección "unida". La dirección 1TP4Búsqueda pasa estos documentos remodelados a la etapa siguiente.

Eliot Horowitz, CTO de MongoDB, dijo: "La agregación de MongoDB es similar al pipeline de Unix. La salida de una etapa va a otra....[es] muy procedimental. Te permite pensar de una manera muy procedimental".

MongoDB $lookup : https://docs.mongodb.com/manual/reference/operator/aggregation/lookup/


¿Quiere saber más sobre las JOIN? Lea el artículo de Lukas Eder. https://dzone.com/articles/a-probably-incomplete-comprehensive-guide-to-the-many-different-ways-to-join-tables-in-sql


Comparación de alto nivel entre Couchbase N1Ql y MongoDB.

Couchbase N1QL: Soporta INNER JOIN, LEFT OUTER JOIN y RIGHT OUTER JOIN limitado. El lenguaje de consulta, como SQL, es declarativo. Los desarrolladores escriben, las herramientas generan la consulta según la sintaxis N1QL. El motor calcula el plan y ejecuta la consulta.

MongoDB: Soporta LEFT OUTER JOIN sólo para valores escalares. El diseño de las uniones en el lenguaje de consulta de MongoDB se realiza para ayudar a escribir la consulta y procesar los datos de forma procedimental. 

Implicación:

  1. El conjunto de resultados de la unión externa izquierda es un superconjunto del conjunto de resultados de la unión interna. Es posible añadir predicados adicionales para eliminar los documentos no coincidentes (proyectados como nulos o que faltan en el lado subordinado de la unión) después de realizar la unión externa izquierda. Es como ir de San Francisco a Chicago pasando por Londres. Se puede hacer, pero es caro. Para la ejecución de la consulta se necesita tiempo, memoria y recursos de cpu, lo que afecta al rendimiento general del sistema.
  2. El soporte de N1QL para joins es declarativo. El lenguaje MongoDB es algo procedimental. Hay que separar los predicados, pensar en el orden de unión entre colecciones, pensar en cuándo agrupar, ordenar, etc. Escribir consultas con agregación en MongoDB es como escribir planes de consulta, paso a paso.

Ejemplos:

Utilizamos el modelo y los datos de la muestra de viaje simple. He aquí los detalles de los datos del modelo. https://developer.couchbase.com/documentation/server/4.5/travel-app/travel-app-data-model.html

Simplemente exportamos los datos desde Couchbase y los importamos a una base de datos mongo llamada travel-sample. En MongoDB, los 5 tipos diferentes del documento (punto de referencia, ruta, aerolínea, aeropuerto, hotel) se almacenan en 5 colecciones con nombres respectivos.

Ejemplo 1: LEFT OUTER JOIN con cláusula ON sobre valores escalares.

Couchbase N1QL

Consulta MongoDB

Observaciones:

Se trata de una consulta bastante sencilla de tipo left outer join que une dos colecciones y luego simplemente cuenta el número total de documentos producidos. Tenga en cuenta que, a diferencia de N1QL (y SQL), en MongoDB, todavía tiene que agrupar el conjunto de resultados para obtener el recuento, incluso si tiene un único grupo.

Ejemplo 2: Enumerar los aeropuertos y lugares emblemáticos de una misma ciudad, ordenados por los aeropuertos.

Couchbase N1QL:

MongoDB:

Observaciones:

  1. Esta consulta utiliza INNER JOIN, que MongoDB no tiene. Por lo tanto, en MongoDB, primero se realiza la unión de búsqueda para obtener el LEFT OUTER JOIN y, a continuación, se eliminan los documentos no coincidentes pero proyectados (debido al left outer) mediante la etapa de coincidencia (código: $match: {"airline_docs": {$ne: []}}).
  2. Luego, hay que recordar que los documentos coincidentes están en una estructura de datos de matriz, desenrollarlos antes de agruparlos por el landmark.name. A continuación, realice la ordenación y la proyección final.

Como era de esperar, la consulta join de MongoDB es procedimental y tienes que entender el plan de ejecución y escribir código para cada etapa.

Ejemplo 3: Partiendo de San Francisco, busque todos los aeropuertos de destino (los que tengan rutas desde SFO).

Couchbase N1QL

MongoDB:

Observaciones:

  1. La cláusula join de esta consulta es un poco más compleja, con dos predicados (airport.faa = (route.sourceairport AND route.type = "route"). Esto requiere una sintaxis de canalización engorrosa en la consulta de MongoDB.
  2. Y como hay que diferenciar entre las dos colecciones, se necesita otra etapa let para crear las variables locales de los atributos del aeropuerto.
  3. Como antes, requiere una cláusula de coincidencia adicional para eliminar los documentos de aerolíneas no coincidentes (vacíos), seguida de agrupación y clasificación.
  4. Como se puede ver visualmente, la consulta MongoDB es cada vez más grande para hacer el mismo trabajo que Couchbase N1QL.

Ejemplo 4: Encontrar todos los hoteles y lugares emblemáticos de Yosemite. Los hoteles deben tener al menos 5 likes.

Couchbase N1QL

MongoDB:

Observación:

  1. Traducir el predicado LIKE en una expresión regular era sencillo, pero determinar si había al menos cinco public_likes no lo era. Se necesitó una fase adicional de proyección y concordancia para calcular el tamaño de los public_likes al final.
  2. Cuando se tienen muchos atributos que comparar, manipular y proyectar, hay que renombrarlos correctamente en el momento oportuno; de lo contrario, la consulta no puede hacer referencia a ellos. Por ejemplo, hotel.name tuvo que ser renombrado a hname antes del desenrollado. Quizá haya una forma mejor de escribir esta etapa.
  3. N1QL expresó la consulta en 370 caracteres. MongoDB requirió 956 caracteres. Todo esto para una unión de dos tablas. A medida que aumenta la complejidad, la proporción también aumenta, ya que la consulta de MongoDB está escrita de forma procedimental.

Ejemplo 5: Encuentra todos los hoteles y lugares emblemáticos de Yosemite. Los hoteles deben tener al menos 5 likes.

Esto es como el ejemplo 4, ¡pero más rápido!

Couchbase N1QL

Observación:

El método join por defecto en Couchbase N1QL es nested loop join. Esto funciona bien cuando tienes un pequeño número de documentos involucrados en cada lado de la unión. Cuando tienes un conjunto de datos más grande, típicamente en consultas de reportes, la unión de bucles anidados se vuelve más lenta. Couchbase N1QL tiene uniones hash y esto acelera las uniones significativamente. Cuando cada lado de la unión tiene de miles a millones de documentos, el incremento de velocidad puede ser de 2x a 20x o más. Ver el blog detallado de Couchbase en Uniones ANSI para más información.

A partir de la documentación y el plan de explicación, no está claro qué método de unión utiliza MongoDB. Algunos de los blogs indican que han utilizado una unión de bucle anidado para implementar el operador $lookup.

Resumen:

 

Couchbase N1QL MongoDB
Enfoque JOIN Declarativo, como SQL.

Permite unir conjuntos de datos de cualquier tamaño y distribuidos.

Procedimental con algunos aspectos declarativos (por ejemplo, selección de índices).

Sólo puede unirse a una colección sharded en un colección sin triturar. Para unir dos colecciones fragmentadas, las aplicaciones tendrán que escribir el algoritmo de unión.

JOINs compatibles LEFT OUTER JOIN

INNER JOIN

UNIÓN EXTERNA DERECHA

$lookup implementa el LEFT OUTER JOIN en valores escalares.
Apoyo a la cláusula ON Expresiones completas.

Escamas

Matrices

Igualdad implícita

Expresión de la tubería

Las matrices deben ser $unwind antes de la $lookup

Aplicación de JOIN Bloque Bucle anidado

Hash join con construcción y sondas definidas por el usuario.

Bucle anidado
Cláusula ON cláusula ON con cualquier expresión. 1TP4Expresión de la línea de producción
Expresiones de matriz en la cláusula ON Utilice las expresiones ANY, IN.

Admite UNNEST

Tubería con $unwind antes de $match
Explique Explicación visual y

JSON explicar

Explicación visual y

JSON explicar

JOIN orden De izquierda a derecha, según especifique el usuario. El optimizador se basa en reglas. Como se especifica en la canalización.
JOINs anidados Soportado mediante tablas derivadas.

La cláusula FROM puede tener subselectas que a su vez pueden tener uniones o subselectas.

No
Tratamiento del predicado JOIN El optimizador procesa los predicados join, predicados constantes y empuja los predicados al índice automáticamente. Diseño manual de predicados para cada colección, ordenación cuidadosa de las etapas del pipeline sin ayuda completa del optimizador.

¿Y el rendimiento? Buena pregunta. Eso es para un futuro blog.

Y ahora, una cita:

"Una frase no debe contener palabras innecesarias, un párrafo frases innecesarias, por la misma razón que un dibujo no debe tener líneas innecesarias y una máquina piezas innecesarias".

- William Strunk, Jr.  Elementos de estilo.

Referencias:

  1. Documentación de Couchbase: https://docs.couchbase.com
  2. Documentación de MongoDB: https://docs.mongodb.com/
  3. Uniones ANSI en Couchbase N1QL: https://www.couchbase.com/blog/ansi-join-support-n1ql/
  4. Tutorial N1QL: https://query-tutorial.couchbase.com/tutorial/#1

Autor

Publicado por Keshav Murthy

Keshav Murthy es Vicepresidente de Couchbase R&D. Anteriormente, estuvo en MapR, IBM, Informix, Sybase, con más de 20 años de experiencia en diseño y desarrollo de bases de datos. Dirigió el equipo de I+D de SQL y NoSQL en IBM Informix. Ha recibido dos premios President's Club en Couchbase y dos premios Outstanding Technical Achievement en IBM. Keshav es licenciado en Informática e Ingeniería por la Universidad de Mysore (India), es titular de diez patentes estadounidenses y tiene tres pendientes.

Dejar una respuesta