sql >> Base de Datos >  >> NoSQL >> MongoDB

¿Por qué las inserciones son lentas en el shell 2.6 MongoDB en comparación con las versiones anteriores?

Antes de la versión 2.6, el shell interactivo se ejecutaba a través del ciclo y solo verificaba el éxito (usando getLastError) de la última operación en el ciclo (más específicamente, llamaba a getLastError después de cada retorno de carro, siendo la última operación la última inserción en el bucle). Con 2.6, el shell ahora verificará el estado de cada operación individual dentro del bucle. Básicamente, eso significa que la "lentitud" con 2.6 se puede atribuir al rendimiento de escritura reconocido frente al no reconocido en lugar de un problema de rendimiento real per se.

Las escrituras reconocidas han sido las predeterminadas desde hace un tiempo , por lo que creo que el comportamiento en el 2.6 es más correcto, aunque un poco inconveniente para aquellos de nosotros que estamos acostumbrados al comportamiento original.

Para volver a sus niveles anteriores de rendimiento, la respuesta es usar el nuevo API de inserción masiva desordenada . Aquí hay una versión 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

Eso ahora vuelve esencialmente al mismo rendimiento en poco más de 2 segundos. Claro, es un poco más voluminoso (perdón por el juego de palabras), pero sabes exactamente lo que obtienes, lo que creo que es algo bueno en general. También hay una ventaja aquí, cuando no está buscando información de tiempo. Deshagámonos de eso y ejecutemos la inserción de nuevo:

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

Ahora obtenemos un buen documento de resultados cuando hacemos la inserción masiva, en lugar de verificar solo las últimas operaciones (todo el resto en la versión 2.4 era esencialmente enviar y olvidar). Debido a que es una operación masiva no ordenada, continuará si encuentra un error e informará sobre cada error en este documento. No se ve ninguno en el ejemplo anterior, pero es fácil crear artificialmente un escenario de falla. Simplemente insertemos previamente un valor que sabemos que aparecerá y, por lo tanto, causará un error de clave duplicada en el índice _id único (predeterminado):

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

Ahora podemos ver cuántos tuvieron éxito, cuál fracasó (y por qué). Puede ser un poco más complicado de configurar, pero en general creo que es una mejora.

Habiendo dicho todo eso, y la nueva forma preferida descrita, hay una manera de hacer que el shell vuelva al modo heredado. Esto tiene sentido, ya que un shell 2.6 podría tener que conectarse y funcionar con servidores más antiguos. Si te conectas a un servidor 2.4, esto se solucionará por ti, pero para forzar el asunto para una conexión en particular puedes ejecutar:

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

Una vez que haya terminado, puede volver a la versión 2.6 con:

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

Para conocer el uso real, consulte mi fragmento de crud.js . Esto funciona por ahora, pero puede eliminarse sin previo aviso en cualquier momento en el futuro y realmente no está diseñado para un uso extensivo, así que utilícelo bajo su propio riesgo.