Le cadre d'agrégation introduit dans mongodb 2.2, a-t-il des améliorations de performances spéciales par rapport à la carte/réduire?
Si oui, pourquoi et comment et combien?
(J'ai déjà fait un test par moi-même et les performances étaient presque les mêmes)
Chaque test que j'ai personnellement exécuté (y compris en utilisant vos propres données) montre que le cadre d'agrégation est plusieurs fois plus rapide que la réduction de la carte, et généralement un ordre de grandeur plus rapide.
Je prends juste 1/10e des données que vous avez publiées (mais plutôt que de vider le cache du système d'exploitation, de réchauffer le cache en premier - parce que je veux mesurer les performances de l'agrégation, et non pas le temps qu'il faut pour parcourir les données), j'ai obtenu ceci:
MapReduce: 1,058ms
Cadre d'agrégation: 133 ms
Suppression de la correspondance $ du cadre d'agrégation et de {query:} de mapReduce (car les deux utiliseraient simplement un index et ce n'est pas ce que nous voulons mesurer) et regroupement de l'ensemble de données par clé2, j'ai obtenu:
Réduction de la carte: 18 803 ms
Cadre d'agrégation: 1 535 ms
Celles-ci sont très conformes à mes expériences précédentes.
Ma référence:
== Génération de données ==
Générez facilement 4 millions de lignes (avec python) avec environ 350 octets. Chaque document a ces clés:
db = Connection('127.0.0.1').test # mongo connection
random.seed(1)
for _ in range(2):
key1s = [hexlify(os.urandom(10)).decode('ascii') for _ in range(10)]
key2s = [hexlify(os.urandom(10)).decode('ascii') for _ in range(1000)]
baddata = 'some long date ' + '*' * 300
for i in range(2000):
data_list = [{
'key1': random.choice(key1s),
'key2': random.choice(key2s),
'baddata': baddata,
'value': 10,
} for _ in range(1000)]
for data in data_list:
db.testtable.save(data)
== Tests ==
J'ai fait quelques tests, mais un suffit pour comparer les résultats:
REMARQUE: le serveur est redémarré et le cache du système d'exploitation est nettoyé après chaque requête, pour ignorer l'effet de la mise en cache.
QUERY: agréger toutes les lignes avec key1=somevalue
(Environ 200 000 lignes) et additionner value
pour chaque key2
requêtes:
cartographier/réduire:
db.testtable.mapReduce(function(){emit(this.key2, this.value);}, function(key, values){var i =0; values.forEach(function(v){i+=v;}); return i; } , {out:{inline: 1}, query: {key1: '663969462d2ec0a5fc34'} })
agrégat:
db.testtable.aggregate({ $match: {key1: '663969462d2ec0a5fc34'}}, {$group: {_id: '$key2', pop: {$sum: '$value'}} })
groupe:
db.testtable.group({key: {key2:1}, cond: {key1: '663969462d2ec0a5fc34'}, reduce: function(obj,prev) { prev.csum += obj.value; }, initial: { csum: 0 } })