Получить большое количество записей с MongoDB в разумные сроки
Я использую mongoDB для хранения журнала запросов и получения статистики об этом. Объекты, которые я храню в mongoDB, содержат текст запроса, дату, пользователя, если пользователь нажал на некоторые результаты и т. Д. И т. Д.
Теперь я пытаюсь получить все запросы, не кликнул пользователь в определенный день с Java. Мой код примерно такой:
DBObject query = new BasicDBObject();
BasicDBObject keys = new BasicDBObject();
keys.put("Query", 1);
query.put("Date", new BasicDBObject("$gte", beginning.getTime()).append("$lte", end.getTime()));
query.put("IsClick", false);
...
DBCursor cur = mongoCollection.find(query, keys).batchSize(5000);
Вывод запроса содержит около 20 тыс. Записей, которые мне нужно перебрать. Проблема в том, что это занимает минуты:( . Я не думаю, что это нормально. Из журнала сервера я вижу:
Wed Nov 16 16:28:40 query db.QueryLogRecordImpl ntoreturn:5000 reslen:252403 nscanned:59260 { Date: { $gte: 1283292000000, $lte: 1283378399999 }, IsClick: false } nreturned:5000 2055ms
Wed Nov 16 16:28:40 getmore db.QueryLogRecordImpl cid:4312057226672898459 ntoreturn:5000 query: { Date: { $gte: 1283292000000, $lte: 1283378399999 }, IsClick: false } bytes:232421 nreturned:5000 170ms
Wed Nov 16 16:30:27 getmore db.QueryLogRecordImpl cid:4312057226672898459 ntoreturn:5000 query: { Date: { $gte: 1283292000000, $lte: 1283378399999 }, IsClick: false } bytes:128015 nreturned:2661 --> 106059ms
Таким образом, извлечение первого блока занимает 2 секунды, второго - 0,1 секунды, третьего - 106 секунд!!! странно... Я пытался изменить размер пакета, создать индексы для Date и IsClick, перезагрузить компьютер:P, но никак. Где я не прав?
1 ответ
Здесь есть несколько факторов, которые могут повлиять на скорость. Необходимо будет собрать некоторые дополнительные данные, чтобы определить причину здесь.
Некоторые потенциальные проблемы:
- Индексы: вы используете правильные индексы? Вы, вероятно, должны индексировать на
IsClick/Date
, Это ставит диапазон на второе место, что является нормальным предложением. Обратите внимание, что это отличается от индексации наDate/IsClick
порядок важен. Попробуйте.explain()
на ваш запрос, чтобы увидеть, какие индексы используются. - Размер данных: в некоторых случаях медлительность может быть вызвана слишком большим количеством данных. Это может быть слишком много документов или слишком много больших документов. Это также может быть вызвано попыткой найти слишком много игл в действительно большом стоге сена. Вы возвращаете 252 КБ в данных (
reslen
) и 12к документов, так что это, вероятно, не проблема. - Дисковый ввод-вывод: MongoDB использует отображенные в памяти файлы и, следовательно, использует много виртуальной памяти. Если у вас больше данных, чем ОЗУ, то выборка определенных документов требует "перехода на диск". Переход на диск может быть очень дорогой операцией. Вы можете идентифицировать "переход на диск" с помощью таких инструментов, как
iostat
или жеresmon
(Windows) для мониторинга активности диска.
Исходя из личного опыта, я сильно подозреваю № 3, с возможным обострением от № 1. Я бы начал с просмотра IO во время запуска .explain()
запрос. Это должно быстро сузить круг возможных проблем.