Поиск записи, где значение находится между двумя полями элементов в MongoDB - PullRequest
2 голосов
/ 09 ноября 2011

У меня есть коллекция MondoDB с более чем 5 миллионами предметов.Каждый элемент имеет поля «начало» и «конец», содержащие целочисленные значения.

Элементы не имеют перекрывающихся начала и конца.

например, это будет недействительно :

{start:100, end:200}
{start:150, end:250}

Я пытаюсь найти элемент, в котором заданное значение находится между началом и концом

start <= VALUE <= end

Следующий запрос работает, но для возврата * 1013 требуется 5-15 секунд*

db.blocks.find({ "start" : { $lt : 3232235521 }, "end" :{ $gt : 3232235521 }}).limit(1);

Я добавил следующие индексы для тестирования с очень небольшим улучшением

db.blocks.ensureIndex({start:1});
db.blocks.ensureIndex({end:1});

//also a compounded one
db.blocks.ensureIndex({start:1,end:1});

** Правка **

Результат объяснения () в результатах запросав:

> db.blocks.find({ "start" : { $lt : 3232235521 }, "end" :{ $gt : 3232235521 }}).limit(1).explain();

{
        "cursor" : "BtreeCursor end_1",
        "nscanned" : 1160982,
        "nscannedObjects" : 1160982,
        "n" : 0,
        "millis" : 5779,
        "nYields" : 0,
        "nChunkSkips" : 0,
        "isMultiKey" : false,
        "indexOnly" : false,
        "indexBounds" : {
                "end" : [
                        [
                                3232235521,
                                1.7976931348623157e+308
                        ]
                ]
        }
}

Как лучше всего ускорить этот конкретный запрос?

Ответы [ 3 ]

3 голосов
/ 05 февраля 2015

На самом деле я работаю над аналогичной проблемой, и мой друг нашел хороший способ решить эту проблему.

Если у вас нет перекрывающихся данных, вы можете сделать это:

  1. запрос с использованием начальное поле и функция сортировки
  2. проверка с конечным полем

, например, вы можете сделать

var x = 100;
var results = db.collection.find({start:{$lte:x}}).sort({start:-1}).limit(1)
if (results!=null) {
  var result = results[0];
  if (result.end > x) {
    return result;
  } else {
    return null; // no range contain x
  } 
}

Если вы уверены, что всегда будет диапазон, содержащий x, вам не нужно проверять результат.

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

--- edit

Я провел некоторый тест, используя составной индекс, требующий 100-100000 мс на запрос, с другой стороны, используяодин индекс занимает 1-5 мс на запрос.

1 голос
/ 09 ноября 2011

Полагаю, что компоновочный индекс должен работать быстрее:

db.blocks.ensureIndex({start:1, end:1});

Вы также можете использовать объяснение , чтобы увидеть количество проверенных объектов и т. Д. И выбрать лучший индекс.

Также, если вы используете mongodb <2.0, вам нужно обновить его до 2.0+, потому что там индексы <a href="http://www.mongodb.org/display/DOCS/2.0+Release+Notes#2.0ReleaseNotes-IndexPerformanceEnhancements" rel="nofollow"> работают быстрее .Также вы можете limit results для оптимизации запроса.

0 голосов
/ 09 ноября 2011

Это может помочь: как насчет того, чтобы ввести некоторую избыточность?Если нет большой разницы в длине интервалов, то вы можете ввести поле тега для каждой записи - это поле тега представляет собой одно значение или строку, которая представляет большой интервал - скажем, например, тег 50 000 используется для тегирования всехзаписи с интервалами, которые хотя бы частично находятся в диапазоне 0-50 000, а тег 100 000 - для всех интервалов в диапазоне 50 000-100 000 и т. д.Теперь вы можете индексировать тег как основной и одну из конечных точек диапазона записи как дополнительный.

Записи на границе большого интервала будут иметь более одного тега - поэтому мы говорим multikeys .По вашему запросу вы, конечно, вычислили бы тег большого интервала и использовали его в запросе.

Вы бы хотели получить SQRT общего количества записей на тег - просто отправную точку для тестов, тогда вы можете точно настроить большойразмер интервала.

Конечно, это может замедлить запись.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...