MongoDB
 sql >> Database >  >> NoSQL >> MongoDB

Perché gli inserti sono lenti nella shell MongoDB 2.6 rispetto alle versioni precedenti?

Prima della 2.6 la shell interattiva eseguiva il ciclo e controllava solo il successo (usando getLastError) dell'ultima operazione nel ciclo (più specificamente, chiamava getLastError dopo ogni ritorno a capo, con l'ultima operazione che è l'ultimo inserimento nel ciclo). Con 2.6, la shell controllerà ora lo stato di ogni singola operazione all'interno del ciclo. In sostanza ciò significa che la "lentezza" con 2.6 può essere attribuita a prestazioni di scrittura riconosciute rispetto a quelle non riconosciute piuttosto che a un problema di prestazioni effettivo di per sé.

Le scritture riconosciute sono state impostazione predefinita ormai da tempo , e quindi penso che il comportamento nella 2.6 sia più corretto, anche se un po' scomodo per quelli di noi abituati al comportamento originale.

Per tornare ai livelli di prestazioni precedenti, la risposta è utilizzare il nuovo API di inserimento collettivo non ordinata . Ecco una versione a tempo:

> 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

Ora è tornato essenzialmente alle stesse prestazioni in poco più di 2 secondi. Certo, è un po' più ingombrante (scusate il gioco di parole), ma sai esattamente cosa stai ricevendo, il che penso sia una buona cosa in generale. C'è anche un vantaggio qui, quando non stai cercando informazioni sui tempi. Eliminiamolo ed eseguiamo di nuovo l'inserto:

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

Ora otteniamo un bel documento di risultati quando eseguiamo l'inserimento in blocco, piuttosto che un controllo solo sulle ultime operazioni (tutto il resto nella versione 2.4 era essenzialmente invia e dimentica). Poiché si tratta di un'operazione in blocco non ordinata, continuerà in caso di errore e riporterà ciascuno di questi errori in questo documento. Non ce ne sono da vedere nell'esempio sopra, ma è facile creare artificialmente uno scenario di errore. Pre-inseriamo semplicemente un valore che sappiamo verrà visualizzato e quindi causerà un errore di chiave duplicata sull'indice _id univoco (predefinito):

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

Ora possiamo vedere quanti hanno avuto successo, quale ha fallito (e perché). Potrebbe essere un po' più complicato da configurare, ma nel complesso penso che sia un miglioramento.

Detto questo, e delineato il nuovo modo preferito, c'è un modo per forzare la shell a tornare alla modalità legacy. Questo ha senso, dal momento che una shell 2.6 potrebbe dover connettersi e lavorare con server meno recenti. Se ti connetti a un server 2.4, questo sarà il tuo problema, ma per forzare la questione per una connessione particolare puoi eseguire:

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

Una volta terminato, puoi tornare alla versione 2.6 con:

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

Per l'utilizzo effettivo, vedere il mio crud.js snippet . Per ora funziona, ma potrebbe essere rimosso senza preavviso in qualsiasi momento in futuro e in realtà non è inteso per un uso estensivo, quindi utilizzalo a tuo rischio.