2014-02-12 1 views
0

Итак, у меня есть экземпляр MongoDB, где я пытаюсь обновить данные в одной коллекции данными из другой коллекции. Две коллекции: participants с документами около 180 тыс. И questions с документами около 95 тыс. Документов.Настройка производительности MongoDB запрос/обновление?

Документы в participants обычно выглядит примерно так:

{ 
    "_id" : ObjectId("52f90b8bbab16dd8594b82b4"), 
    "answers" : [ 
     { 
      "_id" : ObjectId("52f90b8bbab16dd8594b82b9"), 
      "question_id" : 2081, 
      "sub_id" : null, 
      "values" : [ 
       "Yes" 
      ] 
     }, 
     { 
      "_id" : ObjectId("52f90b8bbab16dd8594b82b8"), 
      "question_id" : 2082, 
      "sub_id" : 123, 
      "values" : [ 
       "Would prefer to go alone" 
      ] 
     }, 
     { 
      "_id" : ObjectId("52f90b8bbab16dd8594b82b7"), 
      "question_id" : 2082, 
      "sub_id" : 456, 
      "values" : [ 
       "Yes" 
      ] 
     } 
    ], 
    "created" : ISODate("2012-03-01T17:40:21Z"), 
    "email" : "anonymous", 
    "id" : 65, 
    "survey" : ObjectId("52f41d579af1ff4221399a7b"), 
    "survey_id" : 374 
} 

Я использую запрос ниже, чтобы выполнить обновление:

db.participants.ensureIndex({"answers.question_id": 1, "answers.sub_id": 1}); 
print("created index for answer arrays!") 
db.questions.find().forEach(function(doc){ 
    db.participants.update(
     { 
      "answers.question_id": doc.id, 
      "answers.sub_id": doc.sub_id 
     }, 
     { 
      $set: 
      { 
       "answers.$.question": doc._id 
      } 

     }, 
     false, 
     true 
    ); 
}); 
db.participants.dropIndex({"answers.question_id": 1, "answers.sub_id": 1}); 

Но это занимает около 20 минут, чтобы бежать. Я надеялся, что добавление индекса поможет в производительности, но это все еще довольно медленно. Правильно ли этот индекс настроен, учитывая, что я индексирую поля в массиве объектов? Может ли кто-нибудь увидеть что-нибудь, что я делаю, что приведет к медлительности? Предложения о том, с чего начать искать повышение эффективности этого запроса?

+0

Какой смысл вызывать dropIndex после запроса? Как насчет результата «explain()» вашего запроса? db.participants.find ({ "answers.question_id": doc.id, "answers.sub_id": doc.sub_id }) объяснить() – yaoxing

+0

Я думаю, что это будет намного быстрее, если вы могли бы выразить. это как задание mapreduce, таким образом все это будет выполняться на сервере базы данных без привлечения сети. – leif

+0

Чтобы уточнить, нет отдельного приложения, выполняющего этот скрипт. Это чистый скрипт MongoDB, который я выполняю из оболочки. С учетом сказанного, вы все еще думаете, что сеть задействована? –

ответ

0

В случае, если кто заинтересован я был в состоянии взять время выполнения этого запроса обновления от 20 минут до около минуту и ​​половина, используя проекцию при выборе документов questions. Так как я только с помощью _id, id и sub_id поля я был в состоянии сделать следующее:

db.questions.find({},{_id: 1, id: 1, sub_id: 1}).forEach(function(doc){ 
    .... 

Что резко улучшилось производительность. Надеюсь, это поможет кому-то!

1

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

Первая часть ответа объясняется тем, что вы делаете здесь:

db.questions.find() 

Теперь одна та часть в основном говорит, что вы просите, чтобы получить все документы в вашем questions коллекции. Таким образом, мы можем видеть, что вы пытаетесь сделать именно так, поскольку вы хотите обновить этот контент в своей коллекции participants, в частности документ _id для «вопроса». Но здесь, по определению получения всех документов, индекс не будет использоваться.

Так что вы делаете зацикливание каждый документа в questions, а затем спрашивать с обновление операции на матчемparticipants записи с данными из «вопроса». И что это значит, вы тянете «за провод» все ваши документы 95K и отправляете «по проводам» свою операцию обновления, 95K раз. Это не происходит на сервере, и между вашим приложением и вашим MongoDB существует сетевой трафик.

Этот индекс не будет делать ничего, кроме улучшения поиска каждой записи participants, которая лучше, чем сканирование, и вы должны получить соответствие. Но это не та часть, которая занимает время, ее выборка questions, которая будет самой большой проблемой. Также обратите внимание, что если вы обновляете

Итак, если вы можете запустить процесс обновления на машине, максимально приближенной к сетевым терминам на сервере MongoDB, то это будет вашим лучшим улучшением производительности. Вы также можете открутить свой Write Concern, если хотите быть немного смелым и/или можете жить с проверкой целостности в другой операции, и это уменьшит ваш сетевой трафик и ждет ответа на обновление (которое на самом деле происходит), если вы положили его в «огонь и забыли».

смотрите также руководство, если вы не уверены, понятия:

http://docs.mongodb.org/manual/core/write-concern/

+0

Чтобы уточнить, не существует отдельного приложения, выполняющего этот скрипт. Это чистый скрипт MongoDB, который я выполняю из оболочки. С учетом сказанного, ваши проблемы «по проводам» все еще применяются? –

+0

Да. Оболочка - это еще один клиент. Вы не выполняете на сервере, что, как я думал, вы предполагали, что делаете. –

+0

О, интересно, так можно ли выполнить на сервере? Мой клиент и сервер работают на одном компьютере ... –