Couchbase - MongoDB

Testes com vários usuários

 

David Glasser de Meteoro escreveu um blog sobre um problema de consulta do MongoDB sem documentos correspondentes que ele encontrou. É fácil reproduzir o problema no mecanismo MongoDB MMAPv1 e MongoDB WiredTiger. Aqui estão as conclusões do artigo dele (a ênfase é minha)

 

Resumindo a história...

  • Esse problema não afeta as consultas que não usam um índice, como as consultas que apenas procuram um documento por ID.

  • Isso não afeta as consultas que fazem explicitamente uma correspondência de igualdade de valor único em todos os campos usados na chave do índice.

  • Isso não afeta as consultas que usam índices cujos campos nunca são modificados depois que o documento é inserido originalmente.

  • Mas qualquer outro tipo de consulta ao MongoDB pode não incluir todos os documentos correspondentes!

 

Aqui está outra maneira de ver isso. No MongoDB, se a consulta puder recuperar dois documentos usando um índice secundário (índice em algo diferente de _id) quando operações simultâneas estiverem em andamento, os resultados poderão estar errados. Esse é um cenário comum em muitos aplicativos de banco de dados.

 

Aqui está o teste:

  1. Crie um contêiner: Bucket, tabela ou coleção.

  2. Carregue os dados com um pequeno conjunto de dados, por exemplo, 300 mil documentos.

  3. Crie um índice no campo que você deseja filtrar (predicados).

  4. Em uma sessão, atualize o campo indexado em uma sessão e consulte na outra.

 

Teste do MongoDB

 

Etapas para reproduzir o problema no MongoDB:

 

  1. Instale o MongoDB 3.2.

  2. Crie o mongod com o MMAPv1 ou o WiredTiger.

  3. Carregar dados usando tpcc.py

  4. python tpcc.py -warehouses 1 -no-execute mongodb

  5. Obter a contagem

> use tpcc

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

299890

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

 

Experiência 1 do MongoDB: atualizar para um valor mais alto

 

Configure o campo de estado com o valor aaaaaa e, em seguida, atualize simultaneamente esse valor para zzzzzz e consulte o número total de documentos com os dois valores ['aaaaaa','zzzzzz'] correspondentes ao campo. Quando o valor do campo indexado se move do valor mais baixo (aaaaaa) para o mais alto (zzzzzz), essas entradas estão se movendo de um lado para o outro da árvore B. Agora, estamos tentando ver se a varredura retorna um valor duplicado, traduzido em um valor count() mais alto.

 

> 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" : false,

        "parsedQuery" : {

            "state" : {

                "$in" : [

                    "aaaaaa",

                    "zzzzzz"

                ]

            }

        },

        "winningPlan" : {

            "stage" : "FETCH",

            "inputStage" : {

                "estágio" : "IXSCAN",

                "keyPattern" : {

                    "state" : 1

                },

                "indexName" : "state_1",

                "isMultiKey" : false,

                "direction" : "forward",

                "indexBounds" : {

                    "state" : [

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

                        "["zzzzzz", "zzzzzz"]"

                    ]

                }

            }

        },

        "rejectedPlans" : [ ]

    },

    "serverInfo" : {

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

        "port" : 27017,

        "versão" : "3.0.2",

        "gitVersion" : "6201872043ecbbc0a4cc169b5482dcf385fc464f"

    },

    "ok" : 1

}

 
  1. Declaração de atualização 1: Atualizar todos os documentos para definir state = "zzzzzz"

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

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

 

  1. Declaração de atualização 2: Atualize todos os documentos para definir state = "aaaaaa"

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

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

 

  3. Declaração de contagem: Count documents:(state in ["aaaaaa", "zzzzzz"])

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

 

 
 

Tempo

Sessão 1: Declaração de atualização de problemas1

(atualizar estado = "zzzzzz")

Sessão 2: Declaração de contagem de emissões continuamente.

T0

Início da declaração de atualização

Contagem = 299890

T1

Declaração de atualização continua

Contagem = 312736

T2

Declaração de atualização continua

Contagem = 312730

T3

Declaração de atualização continua

Contagem = 312778

T4

Declaração de atualização continua

Contagem = 312656

T4

Declaração de atualização continua

Contagem = 313514

T4

Declaração de atualização continua

Contagem = 303116

T4

Declaração de atualização concluída

Contagem = 299890

 

Resultado: Nesse cenário, o índice faz uma contagem dupla de muitos documentos e informa mais do que realmente tem.

 

Causa: Os dados no nível de folha da árvore B são classificados. À medida que a atualização da árvore B é atualizada de aaaaaa para zzzzzz, as chaves na extremidade inferior são movidas para a extremidade superior. As varreduras simultâneas não sabem dessa movimentação. O MongoDB não implementa uma varredura estável e conta as entradas à medida que elas chegam. Portanto, em um sistema de produção com muitas atualizações em andamento, ele pode contar o mesmo documento duas, três ou mais vezes. Isso depende apenas das operações simultâneas.

 

Experiência 2 do MongoDB: atualizar para um valor mais baixo

Vamos fazer a operação inversa para atualizar os dados de "zzzzzz" para "aaaaaa". Nesse caso, as entradas do índice estão se movendo de um valor mais alto para um valor mais baixo, fazendo com que a varredura não veja alguns dos documentos qualificados, o que mostra uma subcontagem.

 

Tempo

Sessão 1: Declaração de atualização de problemas2

(update state = "aaaaaa")

Sessão 2: Declaração de contagem de emissões continuamente.

T0

Início da declaração de atualização

Contagem = 299890

T1

Declaração de atualização continua

Contagem = 299728

T2

Declaração de atualização continua

Contagem = 299750

T3

Declaração de atualização continua

Contagem = 299780

T4

Declaração de atualização continua

Contagem = 299761

T4

Declaração de atualização continua

Contagem = 299777

T4

Declaração de atualização continua

Contagem = 299815

T4

Declaração de atualização concluída

Contagem = 299890

 

Resultado: Nesse cenário, o índice perde muitos documentos e informa menos documentos do que realmente tem.

 

Causa: Isso expõe o efeito inverso. Quando as chaves com valores zzzzzz são modificadas para aaaaaa, os itens vão da extremidade superior para a inferior da árvore B. Mais uma vez, como não há estabilidade nas varreduras, ele perderia as chaves que foram movidas da extremidade superior para a inferior.

 

Experiência 3 do MongoDB: UPDATES simultâneas

 

Duas sessões atualizam o campo indexado de forma simultânea e contínua. Nesse caso, com base nas observações anteriores, cada uma das sessões apresenta problemas de supercontagem e subcontagem. O resultado de nModified varia porque o MongoDB relata apenas as atualizações que alteraram o valor.

 

Mas o número total de documentos modificados nunca é maior que 299980. Portanto, o MongoDB evita atualizar o mesmo documento duas vezes, tratando assim o problema clássico de halloween. Como eles não têm uma varredura estável, presumo que lidam com isso mantendo listas de objectIDs atualizados durante essa declaração de várias atualizações e evitando a atualização se o mesmo objeto aparecer como um documento qualificado.

 

SESSÃO 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 })

>

 

SESSÃO 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 })

>

Teste do Couchbase

 

  1. Instale o Couchbase 4.5.

  1. Carregar dados usando tpcc.py

  2. python tpcc.py -warehouses 1 -no-execute n1ql

  3. Obter a contagem

> SELECT COUNT(*) FROM ORDER_LINE;

    300023

  1. CREATE INDEX i1 ON ORDER_LINE(state);

  2. UPDATE ORDER_LINE SET state = 'aaaaaa';

 

Experiência 1 do Couchbase: atualizar para um valor mais alto

 

Faça a configuração inicial.

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

 

Verifique se o campo (atributo) Count. state com valores "aaaaaa" é 300023.

 

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

 UNION ALL

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

   "results": [

       {

           "a_cnt": 300023

       },

       {

           "z_cnt": 0

       }

   ],

 

Vamos garantir que a varredura de índice ocorra na consulta.  

EXPLAIN SELECT COUNT(1) AS totalcnt

DE ORDER_LINE

WHERE state = 'aaaaaa' or state = 'zzzzzz';

             "~children": [

                   {

                       "#operator": "DistinctScan",

                       "scan": {

                           "#operator": "IndexScan",

                           "covers": [

                               "cover ((ORDER_LINE.estado))”,

                               "cover ((meta(ORDER_LINE).id))”

                           ],

                           "index" (índice): "i2",

                           "index_id": "665b11a6c36d4136",

                           "Espaço-chave": "ORDER_LINE",

                           "namespace": "default",

                           "spans": [

                               {

                                   "Range": {

                                       "Alto": [

                                           ""aaaaaa""

                                       ],

                                       "Inclusão": 3,

                                       "Low": [

                                           ""aaaaaa""

                                       ]

                                   }

                               },

                               {

                                   "Range": {

                                       "Alto": [

                                           ""zzzzzz""

                                       ],

                                       "Inclusão": 3,

                                       "Low": [

                                           ""zzzzzz""

                                       ]

                                   }

                               }

                           ],

                           "using": "gsi"

                       }

                   },

 

Também podemos usar UNION ALL de dois predicados separados (state = 'aaaaaa') e (state = 'zzzzzz') para obter a contagem do índice de forma eficiente.  

 

cbq> explain select count(1) a_cnt

DE ORDER_LINE

where state = 'aaaaaa'

UNION ALL

select count(1) z_cnt

DE ORDER_LINE

where state = 'zzzzzz';

{

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

   "signature" (assinatura): "json",

   "results": [

       {

           "plan": {

               "#operator": "UnionAll",

               "children": [

                   {

                       "#operator": "Sequence",

                       "~children": [

                           {

                               "#operator": "IndexCountScan",

                               "covers": [

                                   "cover ((ORDER_LINE.estado))”,

                                   "cover ((meta(ORDER_LINE).id))”

                               ],

                               "index" (índice): "i2",

                               "index_id": "665b11a6c36d4136",

                               "Espaço-chave": "ORDER_LINE",

                               "namespace": "default",

                               "spans": [

                                   {

                                       "Range": {

                                           "Alto": [

                                               ""aaaaaa""

                                           ],

                                           "Inclusão": 3,

                                           "Low": [

                                               ""aaaaaa""

                                           ]

                                       }

                                   }

                               ],

                               "using": "gsi"

                           },

                           {

                               "#operator": "IndexCountProject",

                               "result_terms": [

                                   {

                                       "as": "a_cnt",

                                       "expr": "count(1)"

                                   }

                               ]

                           }

                       ]

                   },

                   {

                       "#operator": "Sequence",

                       "~children": [

                           {

                               "#operator": "IndexCountScan",

                               "covers": [

                                   "cover ((ORDER_LINE.estado))”,

                                   "cover ((meta(ORDER_LINE).id))”

                               ],

                               "index" (índice): "i2",

                               "index_id": "665b11a6c36d4136",

                               "Espaço-chave": "ORDER_LINE",

                               "namespace": "default",

                               "spans": [

                                   {

                                       "Range": {

                                           "Alto": [

                                               ""zzzzzz""

                                           ],

                                           "Inclusão": 3,

                                           "Low": [

                                               ""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'"

       }

   ],

   "status": "success",

   "metrics": {

       "elapsedTime": "2.62144ms",

       "executionTime": "2.597189ms",

       "resultCount": 1,

       "resultSize": 3902

   }

}

 

Configure o campo state com o valor aaaaaa. Em seguida, atualize esse valor para zzzzzz e, ao mesmo tempo, consulte o número total de documentos com um dos dois valores.

 

Sessão 1: Atualizar o campo de estado para o valor zzzzzz

 

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

{    "mutationCount": 300023 }

 

Sessão 2: consultar a contagem de 'aaaaaa' e 'zzzzzz' de ORDER_LINE.

 

Tempo

Sessão 1: Declaração de atualização de problemas1

(atualizar estado = "zzzzzz")

a_cnt

z_cnt

Total

T0

Início da declaração de atualização

300023

0

300023

T1

Declaração de atualização continua

288480

11543

300023

T2

Declaração de atualização continua

259157

40866

300023

T3

Declaração de atualização continua

197167

102856

300023

T4

Declaração de atualização continua

165449

134574

300023

T5

Declaração de atualização continua

135765

164258

300023

T6

Declaração de atualização continua

86584

213439

300023

T7

Declaração de atualização concluída

0

300023

300023

 

Resultado: As atualizações do índice ocorrem à medida que os dados são atualizados. À medida que os valores migram de "aaaaaa" para "zzzzzz", eles não são contados duas vezes.  

 

Os índices do Couchbase fornecem varreduras estáveis por meio de instantâneos do índice em uma frequência regular. Embora esse seja um esforço considerável de engenharia, como vimos nesta edição, ele fornece estabilidade de respostas mesmo em situações extremas de simultaneidade.

 

Os dados que a varredura de índice recupera serão do ponto em que a varredura começa. As atualizações subsequentes que chegarem simultaneamente não serão retornadas. Isso também proporciona outro nível de estabilidade.

 

É importante observar que a estabilidade das varreduras é fornecida para cada varredura de índice. Os índices tiram instantâneos a cada 200 milissegundos. Quando você tem uma consulta de longa duração com várias varreduras de índice no mesmo ou em vários índices, a consulta pode usar vários snapshots. Portanto, diferentes varreduras de índice em uma consulta de longa duração retornarão resultados diferentes. Esse é um caso de uso que melhoraremos em uma versão futura para usar o mesmo snapshot em todas as varreduras de uma única consulta.

Experiência 2 do Couchbase: atualizar para um valor mais baixo

 

Vamos fazer a operação inversa para atualizar os dados de "zzzzzz" de volta para "aaaaaa".

 

Sessão 1: Atualizar o campo de estado para o valor aaaaaa

 

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

{ "mutationCount": 300023 }

 

Sessão 2: consultar a contagem de 'aaaaaa' e 'zzzzzz' de ORDER_LINE.

 

Tempo

Sessão 1: Declaração de atualização de problemas1

(update state = "aaaaaa")

a_cnt

z_cnt

Total

T0

Início da declaração de atualização

0

300023

300023

T1

Declaração de atualização continua

28486

271537

300023

T2

Declaração de atualização continua

87919

212104

300023

T3

Declaração de atualização continua

150630

149393

300023

T4

Declaração de atualização continua

272358

27665

300023

T5

Declaração de atualização continua

299737

286

300023

T6

Declaração de atualização concluída

0

300023

300023

 

Experiência 3 do Couchbase: ATUALIZAÇÕES simultâneas

 

Duas sessões atualizam o campo indexado de forma simultânea e contínua. As varreduras estáveis do índice sempre retornam a lista completa de documentos qualificados: 30023 e o Couchbase atualiza todos os documentos e informa a contagem de mutações como 30023. Uma atualização é uma atualização, independentemente de o valor antigo ser o mesmo que o novo valor ou não.

 

Sessão 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 }

 

Sessão 2:

 

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 }

Conclusões

 

MongoDB:

  1. As consultas do MongoDB perderão documentos se houver atualizações simultâneas que movam os dados de uma parte do índice para outra parte do índice (de cima para baixo).

  2. As consultas do MongoDB retornarão o mesmo documento várias vezes se houver atualizações simultâneas que movam os dados de uma parte do índice para outra parte do índice (de baixo para cima).

  3. As atualizações múltiplas simultâneas no MongoDB terão o mesmo problema e deixarão de atualizar todos os documentos necessários, mas evitam atualizar o mesmo documento duas vezes em uma única instrução.

  4. Ao desenvolver aplicativos que usam o MongoDB, você deve projetar um modelo de dados para selecionar e atualizar apenas um documento para cada consulta. Evite consultas de vários documentos no MongoDB, pois elas retornarão resultados incorretos quando houver atualizações simultâneas.

 

Couchbase:

 

  1. O Couchbase retorna o número esperado de documentos qualificados mesmo quando há atualizações simultâneas. As varreduras de índice estáveis no Couchbase oferecem a proteção ao aplicativo que o MongoDB não oferece.

  2. As atualizações simultâneas se beneficiam de varreduras de índice estáveis e processam todos os documentos qualificados quando a declaração do aplicativo é emitida.

Agradecimentos

Agradecemos a Sriram Melkote e Deepkaran Salooja, da equipe de indexação do Couchbase, pela revisão e pelas valiosas contribuições para este trabalho.

Referências

 

  1. Consistência forte do MongoDB: https://www.mongodb.com/nosql-explained

  2. Concorrência do MongoDB: https://docs.mongodb.com/manual/faq/concurrency/

  3. As consultas do MongoDB nem sempre retornam todos os documentos correspondentes!  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

 

Autor

Postado por Keshav Murthy

Keshav Murthy é vice-presidente de P&D da Couchbase. Anteriormente, ele trabalhou na MapR, IBM, Informix e Sybase, com mais de 20 anos de experiência em design e desenvolvimento de bancos de dados. Ele liderou a equipe de P&D de SQL e NoSQL na IBM Informix. Recebeu dois prêmios President's Club na Couchbase e dois Outstanding Technical Achievement Awards na IBM. Keshav é bacharel em Ciência da Computação e Engenharia pela Universidade de Mysore, Índia, detém dez patentes nos EUA e tem três patentes pendentes nos EUA.

Deixar uma resposta