Alto rendimiento

Comportamiento de la concurrencia: MongoDB vs. Couchbase

Couchbase - MongoDB

Pruebas multiusuario

 

David Glasser de Meteoro escribió un blog sobre una consulta en MongoDB en la que faltan documentos coincidentes con el que se encontró. Es sencillo reproducir el problema tanto en MongoDB MMAPv1 como en el motor MongoDB WiredTiger. Estas son las conclusiones de su artículo (el énfasis es mío)

 

Resumiendo...

  • Este problema no afecta a las consultas que no utilizan un índice, como las consultas que sólo buscan un documento por ID.

  • No afecta a las consultas que realizan explícitamente una coincidencia de igualdad de valor único en todos los campos utilizados en la clave del índice.

  • No afecta a las consultas que utilizan índices cuyos campos nunca se modifican tras la inserción original del documento.

  • Pero cualquier otro tipo de consulta a MongoDB puede no incluir todos los documentos coincidentes.

 

He aquí otra forma de verlo. En MongoDB, si la consulta puede recuperar dos documentos usando un índice secundario (índice sobre algo distinto de _id) cuando se están realizando operaciones concurrentes, los resultados podrían ser erróneos. Este es un escenario común en muchas aplicaciones de bases de datos.

 

Aquí está la prueba:

  1. Crear un contenedor: Cubo, tabla o colección.

  2. Cargue los datos con un pequeño conjunto de datos, digamos 300K documentos.

  3. Cree un índice sobre el campo que desea filtrar (predicados).

  4. En una sesión, actualiza el campo indexado en una sesión y consulta en la otra.

 

Pruebas de MongoDB

 

Pasos para reproducir el problema en MongoDB:

 

  1. Instale MongoDB 3.2.

  2. Sube a mongod con MMAPv1 o WiredTiger.

  3. Cargar datos con tpcc.py

  4. python tpcc.py -almacenes 1 -no-ejecutar mongodb

  5. Obtener el recuento

> use tpcc

> db.ORDER_LINE.find().count();

299890

  1. db.ORDER_LINE.ensureIndex({state:1});

 

Experimento 1 de MongoDB: Actualización a un valor superior

 

Configure el campo de estado con el valor aaaaaa y, a continuación, actualice simultáneamente este valor a zzzzzz y consulte el número total de documentos con los dos valores ['aaaaaa','zzzzzz'] que coinciden con el campo. Cuando el valor del campo indexado pasa del valor más bajo (aaaaaa) al más alto (zzzzzz), estas entradas se mueven de un lado al otro del árbol B. Ahora, estamos tratando de ver si el escaneo devuelve un valor duplicado, traducido a un valor mayor de count().

 

> db.ORDER_LINE.update({OL_DIST_INFO:{$gt:""}}, {$set: {state: "aaaaaa"}}, {multi:true});

WriteResult({"nMatched" : 299890, "nUpserted" : 0, "nModified" : 299890 })

> db.ORDER_LINE.find({state:{$in:['aaaaaa','zzzzzz']}}).count();

299890

 

> db.ORDER_LINE.find({state:{$in:['aaaaaa','zzzzzz']}}).explain();

{

    "queryPlanner" : {

        "plannerVersion" : 1,

        "namespace" : "tpcc.ORDER_LINE",

        "indexFilterSet" : falso,

        "parsedQuery" : {

            "state" : {

                "$in" : [

                    "aaaaaa",

                    "zzzzzz"

                ]

            }

        },

        "winningPlan" : {

            "stage" : "FETCH",

            "inputStage" : {

                "etapa" : "IXSCAN",

                "keyPattern" : {

                    "estado" : 1

                },

                "indexName" : "state_1",

                "isMultiKey" : falso,

                "direction" : "forward",

                "indexBounds" : {

                    "estado" : [

                        "["aaaaaa"", "aaaaaa"]",

                        "["zzzzzz", "zzzzzz"]"

                    ]

                }

            }

        },

        "rejectedPlans" : [ ]

    },

    "serverInfo" : {

        "host" : "Keshavs-MacBook-Pro.local",

        "puerto" : 27017,

        "version" : "3.0.2",

        "gitVersion" : "6201872043ecbbc0a4cc169b5482dcf385fc464f"

    },

    "ok" : 1

}

 
  1. Declaración de actualización 1: Actualizar todos los documentos para establecer state = "zzzzzz"

       db.ORDER_LINE.update({OL_DIST_INFO:{$gt:""}},

                     {$set: {estado: "zzzzzz"}}, {multi:true});

 

  1. Declaración de actualización 2: Actualizar todos los documentos para establecer state = "aaaaaa"

 db.ORDER_LINE.update({OL_DIST_INFO:{$gt:""}},

                     {$set: {estado: "aaaaaa"}}, {multi:true});

 

  3. Declaración de recuento: Contar documentos:(estado en ["aaaaaa", "zzzzzz"])

      db.ORDER_LINE.find({state:{$in:['aaaaaa','zzzzzz']}}).count();

 

 
 

Tiempo

Sesión 1: Declaración de actualización de temas1

(actualizar estado = "zzzzzz")

Sesión 2: Emisión continua de la declaración de recuento.

T0

Comienza la declaración de actualización

Recuento = 299890

T1

Continúa la declaración de actualización

Recuento = 312736

T2

Continúa la declaración de actualización

Recuento = 312730

T3

Continúa la declaración de actualización

Recuento = 312778

T4

Continúa la declaración de actualización

Recuento = 312656

T4

Continúa la declaración de actualización

Recuento = 313514

T4

Continúa la declaración de actualización

Recuento = 303116

T4

Declaración de actualización Realizada

Recuento = 299890

 

Resultado: En este escenario, el índice hace doble recuento de muchos documentos e informa de más de los que realmente tiene.

 

Causa: Los datos en el nivel de hoja del B-Tree están ordenados. Cuando el B-Tree se actualiza de aaaaaa a zzzzzz, las claves del extremo inferior se mueven al extremo superior. Los escaneos concurrentes no son conscientes de este movimiento. MongoDB no implementa un escaneo estable y cuenta las entradas según van llegando. Así, en un sistema de producción con muchas actualizaciones, podría contar el mismo documento dos veces, tres veces o más. Sólo depende de las operaciones concurrentes.

 

Experimento 2 de MongoDB: Actualización a un valor inferior

Hagamos la operación inversa para actualizar los datos de 'zzzzzz' a 'aaaaaa'. En este caso, las entradas del índice pasan de un valor más alto a un valor más bajo, lo que hace que el escaneo pase por alto algunos de los documentos calificados, mostrando un recuento insuficiente.

 

Tiempo

Sesión 1: Declaración de actualización2

(actualizar estado = "aaaaaa")

Sesión 2: Emisión continua de la declaración de recuento.

T0

Comienza la declaración de actualización

Recuento = 299890

T1

Continúa la declaración de actualización

Recuento = 299728

T2

Continúa la declaración de actualización

Recuento = 299750

T3

Continúa la declaración de actualización

Recuento = 299780

T4

Continúa la declaración de actualización

Recuento = 299761

T4

Continúa la declaración de actualización

Recuento = 299777

T4

Continúa la declaración de actualización

Recuento = 299815

T4

Declaración de actualización Realizada

Recuento = 299890

 

Resultado: En este escenario, el índice pasa por alto muchos documentos e informa de menos documentos de los que realmente tiene.

 

Causa: Esto expone el efecto contrario. Cuando las claves con valores zzzzzz se modifican a aaaaaa, los elementos pasan del extremo superior al inferior del B-Tree. De nuevo, como no hay estabilidad en los escaneos, se perderían las claves que se movieran del extremo superior al inferior.

 

Experimento 3 de MongoDB: ACTUALIZACIONES concurrentes

 

Dos sesiones actualizan el campo indexado de forma simultánea y continua. En este caso, basándonos en las observaciones anteriores, cada una de las sesiones se encuentra con un problema tanto de sobreconteo como de infraconteo. El resultado nModified varía porque MongoDB sólo informa de las actualizaciones que han cambiado el valor.

 

Pero el número total de documentos modificados nunca es superior a 299980. Por lo tanto, MongoDB evita actualizar el mismo documento dos veces, manejando así la clásico problema de halloween. Como no tienen un escaneo estable, supongo que manejan esto manteniendo listas de objectIDs actualizados durante esta declaración de actualización múltiple y evitando la actualización si el mismo objeto aparece como un documento calificado.

 

SESIÓN 1

 

> db.ORDER_LINE.update({state:{$gt:""}}, {$set: {state: "aaaaaa"}}, {multi:true});

WriteResult({"nMatched" : 299890, "nUpserted" : 0, "nModified" : 299890 })

> db.ORDER_LINE.update({state:{$gt:""}}, {$set: {state: "zzzzzz"}}, {multi:true});

WriteResult({"nMatched" : 303648, "nUpserted" : 0, "nModified" : 12026 })

> db.ORDER_LINE.update({state:{$gt:""}}, {$set: {state: "aaaaaa"}}, {multi:true});

WriteResult({ "nMatched" : 194732, "nUpserted" : 0, "nModified" : 138784 })

> db.ORDER_LINE.update({state:{$gt:""}}, {$set: {state: "zzzzzz"}}, {multi:true});

WriteResult({ "nMatched" : 334134, "nUpserted" : 0, "nModified" : 153625 })

> db.ORDER_LINE.update({state:{$gt:""}}, {$set: {state: "aaaaaa"}}, {multi:true});

WriteResult({"nMatched" : 184379, "nUpserted" : 0, "nModified" : 146318 })

> db.ORDER_LINE.update({state:{$gt:""}}, {$set: {state: "zzzzzz"}}, {multi:true});

WriteResult({"nMatched" : 335613, "nUpserted" : 0, "nModified" : 153403 })

> db.ORDER_LINE.update({state:{$gt:""}}, {$set: {state: "aaaaaa"}}, {multi:true});

WriteResult({"nMatched" : 183559, "nUpserted" : 0, "nModified" : 146026 })

> db.ORDER_LINE.update({state:{$gt:""}}, {$set: {state: "zzzzzz"}}, {multi:true});

WriteResult({ "nMatched" : 335238, "nUpserted" : 0, "nModified" : 149337 })

> db.ORDER_LINE.update({state:{$gt:""}}, {$set: {state: "aaaaaa"}}, {multi:true});

WriteResult({"nMatched" : 187815, "nUpserted" : 0, "nModified" : 150696 })

> db.ORDER_LINE.update({state:{$gt:""}}, {$set: {state: "zzzzzz"}}, {multi:true});

WriteResult({"nMatched" : 335394, "nUpserted" : 0, "nModified" : 154057 })

> db.ORDER_LINE.update({state:{$gt:""}}, {$set: {state: "aaaaaa"}}, {multi:true});

WriteResult({"nMatched" : 188774, "nUpserted" : 0, "nModified" : 153279 })

> db.ORDER_LINE.update({state:{$gt:""}}, {$set: {state: "zzzzzz"}}, {multi:true});

WriteResult({"nMatched" : 334408, "nUpserted" : 0, "nModified" : 155970 })

> db.ORDER_LINE.update({state:{$gt:""}}, {$set: {state: "zzzzzz"}}, {multi:true});

WriteResult({ "nMatched" : 299890, "nUpserted" : 0, "nModified" : 0 })

>

 

SESIÓN 2:

 

> db.ORDER_LINE.update({state:{$gt:""}}, {$set: {state: "zzzzzz"}}, {multi:true});

WriteResult({"nMatched" : 302715, "nUpserted" : 0, "nModified" : 287864 })

> db.ORDER_LINE.update({state:{$gt:""}}, {$set: {state: "aaaaaa"}}, {multi:true});

WriteResult({ "nMatched" : 195248, "nUpserted" : 0, "nModified" : 161106 })

> db.ORDER_LINE.update({state:{$gt:""}}, {$set: {state: "zzzzzz"}}, {multi:true});

WriteResult({"nMatched" : 335526, "nUpserted" : 0, "nModified" : 146265 })

> db.ORDER_LINE.update({state:{$gt:""}}, {$set: {state: "aaaaaa"}}, {multi:true});

WriteResult({"nMatched" : 190448, "nUpserted" : 0, "nModified" : 153572 })

> db.ORDER_LINE.update({state:{$gt:""}}, {$set: {state: "zzzzzz"}}, {multi:true});

WriteResult({ "nMatched" : 336734, "nUpserted" : 0, "nModified" : 146487 })

> db.ORDER_LINE.update({state:{$gt:""}}, {$set: {state: "aaaaaa"}}, {multi:true});

WriteResult({"nMatched" : 189321, "nUpserted" : 0, "nModified" : 153864 })

> db.ORDER_LINE.update({state:{$gt:""}}, {$set: {state: "zzzzzz"}}, {multi:true});

WriteResult({"nMatched" : 334793, "nUpserted" : 0, "nModified" : 150553 })

> db.ORDER_LINE.update({state:{$gt:""}}, {$set: {state: "aaaaaa"}}, {multi:true});

WriteResult({"nMatched" : 186274, "nUpserted" : 0, "nModified" : 149194 })

> db.ORDER_LINE.update({state:{$gt:""}}, {$set: {state: "zzzzzz"}}, {multi:true});

WriteResult({"nMatched" : 336576, "nUpserted" : 0, "nModified" : 145833 })

> db.ORDER_LINE.update({state:{$gt:""}}, {$set: {state: "aaaaaa"}}, {multi:true});

WriteResult({"nMatched" : 183635, "nUpserted" : 0, "nModified" : 146611 })

> db.ORDER_LINE.update({state:{$gt:""}}, {$set: {state: "zzzzzz"}}, {multi:true});

WriteResult({"nMatched" : 336904, "nUpserted" : 0, "nModified" : 143920 })

>

Pruebas de Couchbase

 

  1. Instale Couchbase 4.5.

  1. Cargar datos con tpcc.py

  2. python tpcc.py -almacenes 1 -no-ejecutar n1ql

  3. Obtener el recuento

> SELECT COUNT(*) FROM LINEA_PEDIDOS;

    300023

  1. CREATE INDEX i1 ON ORDER_LINE(state);

  2. UPDATE ORDER_LINE SET state = 'aaaaaa';

 

Experimento Couchbase 1: Actualización a un valor superior

 

Realiza la configuración inicial.

> UPDATE ORDER_LINE SET state = 'aaaaaa' WHERE OL_DIST_INFO > "";

 

Compruebe que el campo (atributo) Count. state con valores "aaaaaa" es 300023.

 

> select count(1) a_cnt FROM ORDER_LINE where state = 'aaaaaa'

 UNIÓN TODOS

 select count(1) z_cnt FROM ORDER_LINE where state = 'zzzzzz';

   "resultados": [

       {

           "a_cnt": 300023

       },

       {

           "z_cnt": 0

       }

   ],

 

Asegurémonos de que la exploración del índice se produce en la consulta.  

EXPLAIN SELECT COUNT(1) AS totalcnt

DE LÍNEA_PEDIDO

WHERE estado = 'aaaaaa' o estado = 'zzzzzz';

             "~children": [

                   {

                       "#operator": "DistinctScan",

                       "escanear": {

                           "#operator": "IndexScan",

                           "cubiertas": [

                               "tapa ((LÍNEA DE PEDIDO.estado))”,

                               " cubierta ((meta(LÍNEA DE PEDIDO).id))”

                           ],

                           "index": "i2",

                           "index_id": "665b11a6c36d4136",

                           "keyspace": "ORDER_LINE",

                           "namespace": "default",

                           "spans": [

                               {

                                   "Rango": {

                                       "Alto": [

                                           ""aaaaaa""

                                       ],

                                       "Inclusión": 3,

                                       "Bajo": [

                                           ""aaaaaa""

                                       ]

                                   }

                               },

                               {

                                   "Rango": {

                                       "Alto": [

                                           ""zzzzzz""

                                       ],

                                       "Inclusión": 3,

                                       "Bajo": [

                                           ""zzzzzz""

                                       ]

                                   }

                               }

                           ],

                           "using": "gsi"

                       }

                   },

 

También podemos utilizar UNION ALL de dos predicados separados (state = 'aaaaaa') y (state = 'zzzzzz') para que el índice cuente de forma eficiente.  

 

cbq> explain select count(1) a_cnt

DE LÍNEA_PEDIDO

donde estado = 'aaaaaa'

UNIÓN TODOS

select count(1) z_cnt

DE LÍNEA_PEDIDO

donde estado = 'zzzzzz';

{

   "requestID": “ef99e374-48f5-435c-8d54-63d1acb9ad22”,

   "signature": "json",

   "resultados": [

       {

           "plan": {

               "#operator": "UnionAll",

               "niños": [

                   {

                       "#operator": "Secuencia",

                       "~children": [

                           {

                               "#operator": "IndexCountScan",

                               "cubiertas": [

                                   "tapa ((LÍNEA DE PEDIDO.estado))”,

                                   " cubierta ((meta(LÍNEA DE PEDIDO).id))”

                               ],

                               "index": "i2",

                               "index_id": "665b11a6c36d4136",

                               "keyspace": "ORDER_LINE",

                               "namespace": "default",

                               "spans": [

                                   {

                                       "Rango": {

                                           "Alto": [

                                               ""aaaaaa""

                                           ],

                                           "Inclusión": 3,

                                           "Bajo": [

                                               ""aaaaaa""

                                           ]

                                       }

                                   }

                               ],

                               "using": "gsi"

                           },

                           {

                               "#operator": "IndexCountProject",

                               "result_terms": [

                                   {

                                       "as": "a_cnt",

                                       "expr": "count(1)"

                                   }

                               ]

                           }

                       ]

                   },

                   {

                       "#operator": "Secuencia",

                       "~children": [

                           {

                               "#operator": "IndexCountScan",

                               "cubiertas": [

                                   "tapa ((LÍNEA DE PEDIDO.estado))”,

                                   " cubierta ((meta(LÍNEA DE PEDIDO).id))”

                               ],

                               "index": "i2",

                               "index_id": "665b11a6c36d4136",

                               "keyspace": "ORDER_LINE",

                               "namespace": "default",

                               "spans": [

                                   {

                                       "Rango": {

                                           "Alto": [

                                               ""zzzzzz""

                                           ],

                                           "Inclusión": 3,

                                           "Bajo": [

                                               ""zzzzzz""

                                           ]

                                       }

                                   }

                               ],

                               "using": "gsi"

                           },

                           {

                               "#operator": "IndexCountProject",

                               "result_terms": [

                                   {

                                       "as": "z_cnt",

                                       "expr": "count(1)"

                                   }

                               ]

                           }

                       ]

                   }

               ]

           },

           "text": "select count(1) a_cnt FROM ORDER_LINE where state = 'aaaaaa' UNION ALL select count(1) z_cnt FROM ORDER_LINE where state = 'zzzzzz'"

       }

   ],

   "estado": "éxito",

   "métricas": {

       "elapsedTime": "2.62144ms",

       "executionTime": "2.597189ms",

       "resultCount": 1,

       "resultSize": 3902

   }

}

 

Configure el campo de estado con el valor aaaaaa. A continuación, actualice este valor a zzzzzz y consulte simultáneamente el número total de documentos con cualquiera de los dos valores.

 

Sesión 1: Actualizar el campo de estado al valor zzzzzz

 

UPDATE ORDER_LINE SET state = 'zzzzzz' WHERE OL_DIST_INFO > "";

{    "mutationCount": 300023 }

 

Sesión 2: consulta el recuento de 'aaaaaa' y 'zzzzzz' de ORDER_LINE.

 

Tiempo

Sesión 1: Declaración de actualización de temas1

(actualizar estado = "zzzzzz")

a_cnt

z_cnt

Total

T0

Comienza la declaración de actualización

300023

0

300023

T1

Continúa la declaración de actualización

288480

11543

300023

T2

Continúa la declaración de actualización

259157

40866

300023

T3

Continúa la declaración de actualización

197167

102856

300023

T4

Continúa la declaración de actualización

165449

134574

300023

T5

Continúa la declaración de actualización

135765

164258

300023

T6

Continúa la declaración de actualización

86584

213439

300023

T7

Declaración de actualización Realizada

0

300023

300023

 

Resultado: Las actualizaciones del índice se producen a medida que se actualizan los datos. Cuando los valores pasan de "aaaaaa" a "zzzzzz", no se cuentan dos veces.  

 

Los índices de Couchbase proporcionan escaneos estables haciendo snapshots del índice con una frecuencia regular. Aunque se trata de un esfuerzo de ingeniería considerable, como hemos visto en este problema, proporciona estabilidad en las respuestas incluso en situaciones de concurrencia extrema.

 

Los datos que recupere la exploración de índices serán los del punto en que se inicie la exploración. Las actualizaciones posteriores que se produzcan simultáneamente no se devolverán. Esto también proporciona otro nivel de estabilidad.

 

Es importante tener en cuenta que la estabilidad de los escaneos se proporciona para cada escaneo de índice. Los índices toman instantáneas cada 200 milisegundos. Cuando se tiene una consulta de larga ejecución con múltiples escaneos de índices en el mismo o múltiples índices, la consulta podría utilizar múltiples instantáneas. Por lo tanto, diferentes exploraciones de índices en una consulta de larga duración devolverán resultados diferentes. Este es un caso de uso que mejoraremos en una futura versión para utilizar la misma instantánea en todos los escaneos de una misma consulta.

Experimento Couchbase 2: Actualización a un valor inferior

 

Hagamos la operación inversa para actualizar los datos de 'zzzzzz' a 'aaaaaa'.

 

Sesión 1: Actualizar el campo de estado al valor aaaaaa

 

UPDATE ORDER_LINE SET state = 'aaaaaa' WHERE OL_DIST_INFO > "";

{ "mutationCount": 300023 }

 

Sesión 2: consulta el recuento de 'aaaaaa' y 'zzzzzz' de ORDER_LINE.

 

Tiempo

Sesión 1: Declaración de actualización de temas1

(actualizar estado = "aaaaaa")

a_cnt

z_cnt

Total

T0

Comienza la declaración de actualización

0

300023

300023

T1

Continúa la declaración de actualización

28486

271537

300023

T2

Continúa la declaración de actualización

87919

212104

300023

T3

Continúa la declaración de actualización

150630

149393

300023

T4

Continúa la declaración de actualización

272358

27665

300023

T5

Continúa la declaración de actualización

299737

286

300023

T6

Declaración de actualización Realizada

0

300023

300023

 

Experimento Couchbase 3: ACTUALIZACIONES concurrentes

 

Dos sesiones actualizan el campo indexado de forma concurrente y continua. Los escaneos estables del índice siempre devuelven la lista completa de documentos calificados: 30023 y Couchbase actualiza todos los documentos e informa del recuento de mutaciones como 30023. Una actualización es una actualización independientemente de si el valor antiguo es el mismo que el nuevo valor o no.

 

Sesión 1:

 

update ORDER_LINE set state = 'aaaaaa' where state > "";

{ "mutationCount": 300023 }

update ORDER_LINE set state = 'zzzzzz'where state > "";

{ "mutationCount": 300023 }

update ORDER_LINE set state = 'aaaaaa' where state > "";

{ "mutationCount": 300023 }

update ORDER_LINE set state = 'zzzzzz'where state > "";

{ "mutationCount": 300023 }

update ORDER_LINE set state = 'aaaaaa' where state > "";

{ "mutationCount": 300023 }

update ORDER_LINE set state = 'zzzzzz'where state > "";

{ "mutationCount": 300023 }

update ORDER_LINE set state = 'aaaaaa' where state > "";

{ "mutationCount": 300023 }

update ORDER_LINE set state = 'zzzzzz'where state > "";

{ "mutationCount": 300023 }

 

Segunda sesión:

 

update ORDER_LINE set state = 'zzzzzz'where state > "";

{ "mutationCount": 300023 }

update ORDER_LINE set state = 'aaaaaa' where state > "";

{ "mutationCount": 300023 }

update ORDER_LINE set state = 'zzzzzz'where state > "";

{ "mutationCount": 300023 }

update ORDER_LINE set state = 'aaaaaa' where state > "";

{ "mutationCount": 300023 }

update ORDER_LINE set state = 'zzzzzz'where state > "";

{ "mutationCount": 300023 }

update ORDER_LINE set state = 'aaaaaa' where state > "";

{ "mutationCount": 300023 }

update ORDER_LINE set state = 'zzzzzz'where state > "";

{ "mutationCount": 300023 }

Conclusiones

 

MongoDB:

  1. Las consultas de MongoDB perderán documentos si hay actualizaciones concurrentes que muevan los datos de una porción del índice a otra porción del índice (de mayor a menor).

  2. Las consultas de MongoDB devolverán el mismo documento varias veces si hay actualizaciones concurrentes que mueven los datos de una parte del índice a otra parte del índice (de menor a mayor).

  3. Las actualizaciones múltiples concurrentes en MongoDB se encontrarán con el mismo problema y no actualizarán todos los documentos requeridos, pero evitan actualizar el mismo documento dos veces en una sola sentencia.

  4. Cuando desarrolle aplicaciones que utilicen MongoDB, debe diseñar un modelo de datos de forma que sólo seleccione y actualice un documento por cada consulta. Evite las consultas multidocumento en MongoDB ya que devolverá resultados incorrectos cuando haya actualizaciones concurrentes.

 

Couchbase:

 

  1. Couchbase devuelve el número esperado de documentos calificados incluso cuando hay actualizaciones concurrentes. Los escaneos de índices estables en Couchbase proporcionan la protección a la aplicación que MongoDB no ofrece.

  2. Las actualizaciones concurrentes se benefician de escaneos de índices estables y procesan todos los documentos cualificados cuando se emite la declaración de solicitud.

Agradecimientos

Gracias a Sriram Melkote y Deepkaran Salooja del equipo de indexación de Couchbase por su revisión y valiosa aportación al esfuerzo.

Referencias

 

  1. Consistencia sólida de MongoDB: https://www.mongodb.com/nosql-explained

  2. Concurrencia en MongoDB: https://docs.mongodb.com/manual/faq/concurrency/

  3. Las consultas a MongoDB no siempre devuelven todos los documentos coincidentes:  https://engineering.meteor.com/mongodb-queries-dont-always-return-all-matching-documents-654b6594a827#.s9y0yheuv

  4. Couchbase: http://www.couchbase.com

  5. N1QL:  http://query.couchbase.com

 

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

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.

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.