MongoDB
 sql >> Base de données >  >> NoSQL >> MongoDB

Pourquoi les insertions sont-elles lentes dans le shell MongoDB 2.6 par rapport aux versions précédentes ?

Avant 2.6, le shell interactif parcourait la boucle et ne vérifiait que le succès (à l'aide de getLastError) de la dernière opération de la boucle (plus précisément, il s'appelait getLastError après chaque retour chariot, la dernière opération étant la dernière insertion dans la boucle). Avec 2.6, le shell vérifiera désormais l'état de chaque opération individuelle dans la boucle. Cela signifie essentiellement que la "lenteur" avec 2.6 peut être attribuée aux performances d'écriture reconnues par rapport aux performances non reconnues plutôt qu'à un problème de performances réel en soi.

Les écritures reconnues ont été par défaut depuis quelque temps , et donc je pense que le comportement dans la 2.6 est plus correct, bien qu'un peu gênant pour ceux d'entre nous habitués au comportement d'origine.

Pour revenir à vos niveaux de performance précédents, la réponse est d'utiliser le nouveau API d'insertion en masse non ordonnée . Voici une version chronométrée :

> 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

C'est maintenant de retour à essentiellement la même performance à un peu plus de 2 secondes. Bien sûr, c'est un peu plus volumineux (pardonnez le jeu de mots), mais vous savez exactement ce que vous obtenez, ce qui, à mon avis, est une bonne chose en général. Il y a aussi un avantage ici, lorsque vous ne recherchez pas d'informations sur le timing. Débarrassons-nous de cela et exécutons à nouveau l'insertion :

> 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" : [ ]
})

Maintenant, nous obtenons un beau document de résultat lorsque nous effectuons l'insertion en bloc, plutôt qu'une vérification des dernières opérations uniquement (tout le reste dans la version 2.4 était essentiellement envoyer et oublier). Comme il s'agit d'une opération en bloc non ordonnée, elle se poursuivra si elle rencontre une erreur et signalera chacune de ces erreurs dans ce document. Il n'y en a pas dans l'exemple ci-dessus, mais il est facile de créer artificiellement un scénario d'échec. Pré-insérons simplement une valeur dont nous savons qu'elle apparaîtra et provoquera donc une erreur de clé en double sur l'index _id unique (par défaut) :

> 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" : [ ]
})

Maintenant, nous pouvons voir combien ont réussi, lequel a échoué (et pourquoi). C'est peut-être un peu plus compliqué à mettre en place, mais dans l'ensemble je pense que c'est une amélioration.

Avec tout cela dit, et la nouvelle méthode préférée décrite, il existe un moyen de forcer le shell à revenir en mode hérité. Cela a du sens, car un shell 2.6 peut avoir à se connecter et à travailler avec des serveurs plus anciens. Si vous vous connectez à un serveur 2.4, cela sera pris en charge pour vous, mais pour forcer le problème pour une connexion particulière, vous pouvez exécuter :

db.getMongo().forceWriteMode("legacy");

Une fois que vous avez terminé, vous pouvez revenir à la version 2.6 avec :

db1.getMongo().forceWriteMode("commands");

Pour une utilisation réelle, consultez mon extrait crud.js . Cela fonctionne pour le moment, mais peut être supprimé sans préavis à tout moment dans le futur et n'est vraiment pas destiné à une utilisation intensive, donc utilisez-le à vos risques et périls.