Оптимизированный способ обновления большого встроенного массива в документе mon go с помощью индексированного ключа - PullRequest
1 голос
/ 22 февраля 2020

У меня есть пользовательская коллекция с 52 миллионами записей. Каждый пользовательский документ имеет список комментариев, и comment_id имеет уникальный индекс.

{
  _id:123, 
  user_name:"xyz",
  comments:[
    {
      comment_id:123,
      text:"sd"
    },
    {
      comment_id:234,
      text:"sdf"
    }
    ......,
    (63000 elements)
  ]
}

totalIndexSize индекса comment_id составляет 104 ГБ. У меня есть около 100 документов из 52M, которые имеют 63000 элементов в массиве комментариев.

Моя цель - удалить старые комментарии и уменьшить размер массива комментариев более чем на 80%. Ранее, когда я пытался обновить документ с помощью этого запроса

db.user.updateOne({_id:_id},{$set: {"comments":newCommentsArray}},upsert=True)

, здесь newCommentsArray будет иметь размер около 400. Для выполнения этой операции потребовалось около 130 se c.

Мои вопросы являются:

1) Что может быть причиной запроса обновления выше 130se c. Это из-за огромного уникального размера индекса в поле comment_id? (Я считаю, что при обновлении массива комментариев новым массивом комментариев будет пытаться изменить порядок индекса для всех удаленных 63000 элементов и вставить новые элементы в индекс.)

2) У меня был другой подход, использующий $pull который в основном извлекает 100 комментариев из массива комментариев и ждет 5 сек c, а затем выполняет следующую партию из 100 комментариев. Что вы думаете об этом решении.

3) Если вышеприведенное решение бесполезно, можете ли вы предложить хороший способ уменьшить массив комментариев более чем на 80%.

1 Ответ

1 голос
/ 23 февраля 2020

У вас огромный индекс для comment_id, потому что у вас есть Индекс нескольких ключей

MongoDB создает ключ индекса для каждого элемента в массиве.

В вашем случае индекс _id имеет размер ~ 1 ГБ, comment_id равен avg ~100/per document (для получения ~ 104 ГБ)

1) Что может быть причиной, по которой запрос обновления, приведенный выше, занял 130se c

Mongodb хранит индексы с структурой B-дерева . Свойства B-дерева:

Algorithm   Average     Worst case
Space       O(n)        O(n)
Search      O(log n)    O(log n)
Insert      O(log n)    O(log n)
Delete      O(log n)    O(log n)

Это означает, что для вставки индексов для комментариев MongoDB необходимо выполнить итерацию O(log n) (~ 25 итераций для каждого элемента) в худшем случае.

2) У меня был другой подход, использующий $ pull, который в основном извлекает 100 комментариев из массива комментариев и ждет 5 сек c, а затем выполняет следующий пакет из 100 комментариев.

Поскольку комментарии индексируются, это будет fast (помните свойство O (log n)). Не нужно ждать 5 секунд, поскольку начиная с MongoDB 3.0 он использует мульти-гранулярную блокировку , что означает блокировку только затронутых документов.

Кроме того, вы можете уменьшить оператор $push следующим образом:

db.user.update({ },{$push: {comments: {$each: [ ], $slice: -400}}})

Это вставит [ ] (в данном случае 0 предметов) предметов и нарежет 400 предметов с конца

3) Если вышеприведенное решение бесполезно, можете ли вы Предложите хороший способ уменьшить массив комментариев более чем на 80%.

Даже если вы уменьшите массив комментариев, WiredTiger не освободит ненужное дисковое пространство для операционной системы .

Выполняется dropIndex

db.user.dropIndex({ "comment_id" : 1 })

Предупреждение: Поскольку v4.2 получает эксклюзивную блокировку для указанной коллекции на время операции. Все последующие операции над коллекцией должны ждать, пока db.collection.dropIndex () снимет блокировку.

До версии 4.2 эта команда получает блокировку записи в уязвимой базе данных и будет блокировать другие операции, пока она не завершится. ,

Или работает compact

Предупреждение: compact блокирует операции для базы данных, в которой он в данный момент работает. Используйте compact только во время планового технического обслуживания. Кроме того, вы должны аутентифицироваться как user с компактным действием привилегий в целевой коллекции

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