Подтвердить что ты не робот

Производительность MongoDB по агрегационным запросам

После того, как вы услышали много хорошего о производительности MongoDB, мы решили дать Mongodb попытку решить проблему, которая у нас есть. Я начал с перемещения всех записей, которые мы имеем в нескольких базах данных mysql, в одну коллекцию в mongodb. Это привело к созданию коллекции с 29 миллионами документов (каждая из них имеет не менее 20 полей), что занимает около 100 ГБ пространства в HD. Мы решили поместить их все в одну коллекцию, поскольку все документы имеют одинаковую структуру, и мы хотим запросить и агрегировать результаты по всем этим документам.

Я создал некоторые индексы для соответствия моим запросам, иначе даже простой счетчик() займет много времени. Тем не менее, запросы, такие как distinct() и group(), все еще занимают слишком много времени.

Пример:

// creation of a compound index    
db.collection.ensureIndex({'metadata.system':1, 'metadata.company':1})

// query to get all the combinations companies and systems
db.collection.group({key: { 'metadata.system':true, 'metadata.company':true }, reduce: function(obj,prev) {}, initial: {} });

Я просмотрел журнал mongod и у него много таких строк (при выполнении запроса выше):

Thu Apr  8 14:40:05 getmore database.collection cid:973023491046432059 ntoreturn:0 query: {}  bytes:1048890 nreturned:417 154ms
Thu Apr  8 14:40:08 getmore database.collection cid:973023491046432059 ntoreturn:0 query: {}  bytes:1050205 nreturned:414 430ms
Thu Apr  8 14:40:18 getmore database.collection cid:973023491046432059 ntoreturn:0 query: {}  bytes:1049748 nreturned:201 130ms
Thu Apr  8 14:40:27 getmore database.collection cid:973023491046432059 ntoreturn:0 query: {}  bytes:1051925 nreturned:221 118ms
Thu Apr  8 14:40:30 getmore database.collection cid:973023491046432059 ntoreturn:0 query: {}  bytes:1053096 nreturned:250 164ms
...
Thu Apr  8 15:04:18 query database.$cmd ntoreturn:1 command  reslen:4130 1475894ms

Этот запрос занял 1475894ms, что намного дольше, чем я ожидал (список результатов насчитывает около 60 записей). Прежде всего, это ожидалось, учитывая большое количество документов в моей коллекции? Ожидают ли, что запросы агрегирования в mongodb будут настолько медленными? Любые мысли о том, как я могу улучшить производительность?

Я запускаю mongod в одной машине с двухъядерным и 10 ГБ памяти.

Спасибо.

4b9b3361

Ответ 1

Идея заключается в том, что вы улучшаете производительность запросов агрегирования, используя MapReduce в оштрафованной базе данных, которая распределяется по нескольким машинам.

Я сделал несколько сравнений производительности Mongo Mapreduce с оператором group-by-select в Oracle на той же машине. Я обнаружил, что Монго был примерно в 25 раз медленнее. Это означает, что я должен очертить данные по меньшей мере на 25 машинах, чтобы получить ту же производительность с Mongo, что и Oracle, на одной машине. Я использовал коллекцию/таблицу с примерно 14 миллионами документов/строк.

Экспорт данных из mongo через mongoexport.exe и использование экспортированных данных в качестве внешней таблицы в Oracle и выполнение групповой работы в Oracle было намного быстрее, чем использование Mongo собственного MapReduce.

Ответ 2

Пара вещей.

1) Ваш групповой запрос обрабатывает множество данных. Хотя ваш результирующий набор невелик, похоже, что он выполняет таблицу масштаба всех данных в вашей коллекции, чтобы создать этот небольшой результат. Вероятно, это является основной причиной медленности. Чтобы ускорить это, вы можете посмотреть на производительность вашего сервера через iostat во время выполнения запроса, поскольку это, скорее всего, является узким местом.

2) Как было указано в других ответах, команда группы использует интерпретатор javascript, который ограничивает производительность. Вы можете попробовать использовать новую структуру агрегации, выпущенную как бета-версию в 2.1 (обратите внимание: это нестабильная версия по состоянию на 24 февраля 2012 года). См. http://blog.mongodb.org/post/16015854270/operations-in-the-new-aggregation-framework для хорошего ознакомления. Это не будет преодолевать проблему объема данных в (1), но реализовано на С++, и если время javascript является узким местом, то это должно быть намного быстрее.

3) Другим подходом было бы использование инкрементного сокращения карты для создания второй коллекции с вашими сгруппированными результатами. Идея заключается в том, что вы запускаете работу по сокращению карты, чтобы агрегировать свои результаты один раз, а затем периодически запускать другую работу по сокращению карты, которая сводит к минимуму новые данные в существующую коллекцию. Затем вы можете запросить эту вторую коллекцию из своего приложения, а не запускать групповую команду каждый раз.

Ответ 3

Агрегация (уменьшение карты или иное) очень медленна в mongo, потому что это делается с помощью javascript VM, а не с движком базы данных. Это по-прежнему является ограничением этого (очень хорошего, imo) db для данных временных рядов.