Оптимизация для точного сопоставления массива по коллекции MongoDB - PullRequest
3 голосов
/ 18 января 2012

У меня есть коллекция, где мне нужно только искать документы по целым массивам; Я не могу вспомнить ни одного сценария, в котором я хотел бы искать документы только по одному значению этого массива. К сожалению, функция нескольких клавиш, которая всегда активируется для значений массива, очевидно, не может быть деактивирована.

В документации говорится: «Индекс будет использоваться для поиска подмножества значений (в настоящее время первого), а затем документ будет проверен на точное совпадение». снижает производительность в моем случае. Несмотря на индекс, некоторые поиски занимают 70 мс, а некоторые - несколько минут, потому что, в зависимости от первого элемента, MongoDB иногда приходится искать в нескольких тысячах или нескольких сотнях тысяч документов. По крайней мере, это моя теория.

Есть ли способ избежать этой проблемы, или мне лучше сериализовать мои массивы и хранить их как строки?

Заранее спасибо!

1 Ответ

1 голос
/ 18 января 2012

Возможно, вы могли бы использовать под-документ, например:

{
  array_sub_doc: { arr: [1,2,3,4,5] }
}

, чтобы вы могли делать такие совпадения, как:

db.coll.ensureIndex({array_sub_doc:1});
db.coll.find({array_sub_doc: {arr:[1,2,3,4,5]}})

обновление Я обнаружил, что вызвало сбойдля больших массивов.Индексные ключи> 800 байт не будут проиндексированы.Итак, если у вас большой поддокумент и вы поместили в него индекс, если он больше 800 байт, и вы пытаетесь найти его, вы его не найдете.Если вы отключите индекс и снова выполните поиск того же поддокумента, вы найдете его (хотя это будет полное сканирование коллекции).

Это задокументировано здесь как ограничение и будет удалено в будущем.релизы: https://jira.mongodb.org/browse/SERVER-3372

Итак, в целом, для небольших массивов это будет работать.

Вот несколько тестовых кодов на случай, если кто-нибудь захочет попробовать:

var randomArray = function() {
  var len = 80;
  var randomarr = new Array();
  for (var i=0; i<len; i++) {
    randomarr.push(Math.floor(Math.random() *10000));
  }
  return randomarr;
}

var insert = function() {
  db.Test2.ensureIndex({array_sub_doc:1});
  for(var i=0;i<10000;i++) {
    db.Test2.save({array_sub_doc: {arr: randomArray()}});
  }
}

db.Test2.remove();
insert();

var one = db.Test2.findOne();
db.Test2.findOne({array_sub_doc:one.array_sub_doc});

//...

db.Test2.find({array_sub_doc:one.array_sub_doc}).explain(0);
/* outputs:
{
  "cursor" : "BtreeCursor array_sub_doc_1",
  "nscanned" : 1,
  "nscannedObjects" : 1,
  ...
*/
...