Монго оптимизация: производительность запросов против структуры базы данных - PullRequest
0 голосов
/ 07 сентября 2018

Контекст: приложение NodeJs (meteorjs), подключенное к серверу MongoDB 4.0

У меня есть набор данных, которые я вычисляю довольно часто, и которые мне нужны для хранения времени, а затем доступа к определенному набору данных из моего приложения. Набор представляет собой массив из 12 000 объектов, конечный вес которого составляет около 3 МБ (измеряется с использованием статистики коллекции MongoDB для Коллекции только с одним набором данных: размер: 3,3 МБ; количество: 12964). Это связано с некоторыми параметрами вычислений. Мне нужно получить набор с помощью запроса.

Мне нужно выбрать между двумя структурами базы данных:

Вариант 1: В одной коллекции хранятся ссылки на вычисления с идентификатором (назовем его ReferenceCollection), а в другой коллекции - все 12000 объектов на вычисления, сохраненные в виде отдельных документов, и referenceId, указывающий на созданный ранее идентификатор.

Вот схематическое представление:

ReferenceCollection :
|--- _id: ObjectId("a")
|--- computation : "my reference"

ResultCollection : 
|--- _id: ObjectId("b")
|--- referenceId : ObjectId("a")
|--- fieldResut1 : data
.
.
|--- fieldResut20 : data

Чтобы получить набор, я запросил бы referenceId в первой коллекции, используя параметры вычисления), затем запросил второй со ссылочным Id, чтобы получить 12 000 документов.

let reference = ReferenceCollection.findOne({computation: "my reference"}) // this is lightweight
let results = ResultCollection.find({referenceId: reference._id}) // this search for the 12 000 results

Вариант 2: Одна коллекция, хранящая ссылки на вычисления с ключом, содержащим массив с данными внутри

Вот схематичное представление:

ResultCollection : 
|--- _id: ObjectId("b")
|--- computation : "my reference"
|--- result : Array(    
    |--- fieldResut1 : data
    .
    .
    |--- fieldResut20 : data
)

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

Проблема: У меня возникают проблемы с производительностью при первом варианте: запрос и получение всех 12000 документов из настольного клиента MongoDB (студия 3T) довольно медленный: у меня 3 секунды. Второй вариант занимает всего 1 секунду для извлечения (это время включает загрузку данных). Это заставляет мое приложение долго ждать при получении данных.

Запросы из mongoshell на сервере выполняются очень быстро при возврате курсоров (около 20 мс для варианта 1).


Можете ли вы подтвердить, что вариант 2 является хорошим выбором для хранения этих данных?

Есть ли у меня другие варианты в отношении структуры данных?

Я запускаю MongoDB на одном узле. Считаете ли вы, что установка набора реплик может помочь улучшить производительность чтения?

1 Ответ

0 голосов
/ 18 сентября 2018

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

Вариант 1, который вы бы использовали, если, например, набор пользователей, на которые есть ссылки в наборе транзакций.

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

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

Если вам нужно соединить две коллекции Mongo, рассмотрите возможность использования агрегации, чтобы сервер Mongo мог получать данные за 1 попадание по сравнению с необходимостью выполнять несколько запросов.

EDIT:

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

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

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

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