MongoDB
 sql >> Base de Dados >  >> NoSQL >> MongoDB

Por que as inserções são lentas no shell 2.6 do MongoDB em comparação com as versões anteriores?


Antes da versão 2.6, o shell interativo executava o loop e apenas verificava o sucesso (usando getLastError) da última operação no loop (mais especificamente, chamava getLastError após cada retorno de carro, com a última operação sendo a última inserção no loop). Com 2.6, o shell agora verificará o status de cada operação individual dentro do loop. Essencialmente, isso significa que a "lentidão" com 2.6 pode ser atribuída ao desempenho de gravação reconhecido versus não reconhecido, em vez de um problema de desempenho real em si.

As gravações reconhecidas foram o padrão já faz algum tempo , e por isso acho que o comportamento no 2.6 é mais correto, embora um pouco inconveniente para quem está acostumado com o comportamento original.

Para voltar aos níveis anteriores de desempenho, a resposta é usar o novo API de inserção em massa não ordenada . Aqui está uma versão cronometrada:
> db.timecheck.drop();
true
> var bulk = db.timecheck.initializeUnorderedBulkOp(); start = new Date(); for(var i = 0; i < 100000; i++){bulk.insert({"_id" : i})}; bulk.execute({w:1}); end = new Date(); print(end - start);
2246

Isso agora está de volta essencialmente ao mesmo desempenho em pouco mais de 2 segundos. Claro, é um pouco mais volumoso (desculpe o trocadilho), mas você sabe exatamente o que está recebendo, o que acho bom em geral. Há também uma vantagem aqui, quando você não está procurando informações de tempo. Vamos nos livrar disso e executar a inserção novamente:
> db.timecheck.drop();
true
> var bulk = db.timecheck.initializeUnorderedBulkOp(); for(var i = 0; i < 100000; i++){bulk.insert({"_id" : i})}; bulk.execute({w:1});
BulkWriteResult({
"writeErrors" : [ ],
"writeConcernErrors" : [ ],
"nInserted" : 100000,
"nUpserted" : 0,
"nMatched" : 0,
"nModified" : 0,
"nRemoved" : 0,
"upserted" : [ ]
})

Agora obtemos um bom documento de resultado quando fazemos a inserção em massa, em vez de verificar apenas as últimas operações (todo o resto na versão 2.4 era essencialmente enviar e esquecer). Por ser uma operação em massa não ordenada, ela continuará se encontrar um erro e relatará cada erro neste documento. Não há nenhum para ser visto no exemplo acima, mas é fácil criar artificialmente um cenário de falha. Vamos apenas pré-inserir um valor que sabemos que aparecerá e, portanto, causará um erro de chave duplicada no índice _id exclusivo (padrão):
> db.timecheck.drop();
true
> db.timecheck.insert({_id : 500})
WriteResult({ "nInserted" : 1 })
> var bulk = db.timecheck.initializeUnorderedBulkOp(); for(var i = 0; i < 100000; i++){bulk.insert({"_id" : i})}; bulk.execute({w:1});
2014-03-28T16:19:40.923+0000 BulkWriteError({
"writeErrors" : [
{
"index" : 500,
"code" : 11000,
"errmsg" : "insertDocument :: caused by :: 11000 E11000 duplicate key error index: test.timecheck.$_id_ dup key: { : 500.0 }",
"op" : {
"_id" : 500
}
}
],
"writeConcernErrors" : [ ],
"nInserted" : 99999,
"nUpserted" : 0,
"nMatched" : 0,
"nModified" : 0,
"nRemoved" : 0,
"upserted" : [ ]
})

Agora podemos ver quantos foram bem-sucedidos, qual falhou (e por quê). Pode ser um pouco mais complicado de configurar, mas no geral acho que é uma melhoria.

Com tudo isso dito, e a nova maneira preferida delineada, existe uma maneira de forçar o shell de volta ao modo legado. Isso faz sentido, já que um shell 2.6 pode ter que se conectar e trabalhar com servidores mais antigos. Se você se conectar a um servidor 2.4, isso será resolvido para você, mas para forçar o problema para uma conexão específica, você pode executar:
db.getMongo().forceWriteMode("legacy");

Quando terminar, você pode reverter para a versão 2.6 com:
db1.getMongo().forceWriteMode("commands");

Para uso real, veja meu crud.js snippet . Isso funciona por enquanto, mas pode ser removido sem aviso a qualquer momento no futuro e realmente não se destina a uso extensivo, portanto, use por sua conta e risco.