Проблема индексации встроенных документов MongoDB

У меня есть данные в коллекции mongodb в следующем формате:

{
    _id: ObjectId,
    Product: string,
    Modules: [
        {
            StaticModuleId: Int64,
            Set: [
                {
                    k: Int64,
                    v: {
                        Value: Double,
                        AnotherId: Int64


            }
            },
            ...
        ]
    }, 
    ...
]

}

Вот мой индекс с именем MyIndex:

{
    Product: 1,
    'Modules.StaticModuleId': 1,
    'Modules.Set.k': 1,
    'Modules.Set.v.Value': 1
}

В сборнике 5 документов, в каждом из которых по 10 модулей и 100 элементов в каждом наборе, всего 50 модулей и 5000 записей в наборе. Затем я выполнил этот запрос:

{
    'Product': 'Test',
    $and: [
        {
            'Modules.StaticModuleId': 2010220,
            'Modules.Set': {
                $elemMatch: {
                    k: 41439,
                    'v.Value': 2186233
                }
            }
        },
        {
            'Modules.StaticModuleId': 2010226
        },
        {
            'Modules.StaticModuleId': 2010228
        }
    ]
}

Вот .explain():

{
    cursor: 'BtreeCursor MyIndex',
    isMultiKey: true,
    n: 4,
    nscannedObjects: 941,
    nscanned: 941,
    nscannedObjectsAllPlans: 941,
    nscannedAllPlans: 941,
    scanAndOrder: false,
    indexOnly: false,
    nYields: 0,
    nChunkSkips: 0,
    millis: 52  
}

Поскольку я продолжаю добавлять дополнительные предложения $elemMatch, производительность снижается до> 200 мс. Можно ли индексировать этот тип запроса, и если да, то есть ли какие-либо идеи относительно того, как я могу улучшить производительность?


person Jason Fry    schedule 22.04.2013    source источник
comment
почему у вас есть выражение $and? Почему бы просто не перечислить все условия, разделенные символом ','?   -  person Asya Kamsky    schedule 23.04.2013
comment
Я считаю, что при попытке индексировать внутри elemmath возникают проблемы, см. stackoverflow. com/questions/10207448/ IMO, вы можете подумать о том, чтобы сделать ваши модули первоклассными гражданами.   -  person Fatmuemoo    schedule 23.04.2013


Ответы (2)


попробуйте удалить предыдущий индекс и создать с многоключевым флагом, например:

db.collection.ensureIndex({{'Product':1, 'Modules.StaticModuleId':1, 'Modules.Set':1, 'Modules.Set.k':1, 'Modules.Set.v.Value':1}, {multikey:true})

в моем тестовом примере у меня есть только 100 отсканированных объектов и миллис = 0

подсказка: вы можете загружать данные и/или индексировать в память:

db.runCommand({ touch: "collection", data: true, index: true })

Я использую следующий скрипт для воспроизведения проблемы и подготовки данных:

for(var prod=0; prod<1000; prod++) {
    prodObj={Product:"product" + prod};
    modObj=[];
    for(var mod=0; mod < 10; mod++) {
        seObj=[];
        for(var se=0; se < 100; se++) {
            seObj[se] = {k: "Int64-" + se, v:{Value:"Double-" + se}, AnotherId:"Int64"};
        }
        modObj[mod]={StaticModuleId:"Int64-"+prod, Set:seObj};
    }
    prodObj.Modules=modObj;
    db.so.insert(prodObj);
}

может быть это не правильное для вас задание

person Vladimir Muzhilov    schedule 24.04.2013
comment
Я создал индекс с помощью простого «Modules.Set»: 1, и он работал без проблем. - person Jason Fry; 24.04.2013

Я думаю, что модель данных не так хороша. Это отношения типа модели. Если вы можете изменить модель данных на простую, например:

{
  Product: "string",
  StaticModuleId: "string",
  Set:
  [
    {
      k: "string",
      v: 
      {
        Value: "double",
        AnotherId: "string"
      }
    }
  ]
}

у вас будет более хорошая производительность и меньшая сложность

person Vladimir Muzhilov    schedule 24.04.2013