Лучший выбор сделать мультисчет с точки зрения производительности в MongoDB? - PullRequest
0 голосов
/ 17 июня 2019

Я должен сделать несколько подсчетов в MongoDB.У меня есть коллекция документов (около 1,5 миллионов), например:

reportDocument
{
  _id : Guid,
  status : number (enum value),
  name : string
}

с пользовательским индексом

{
    name : 1,
    status : 1
}

Моя цель - получить счетчик для каждого имени, подобного этому

{
    inProgress : 3,
    completed : 2,
    canceled : 4
}

У меня есть два обходных пути.Во-первых, просто используйте счет 3 раза

db.reports.count({name : "name", status : 2}) // for canceled, completed etc

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

1-й

Объясните мне, что это коллскан, что, на мой взгляд, плохо, поэтому я изменил это во второй

db.reports.aggregate([
  { "$facet": {
    "inProgress": [
      { "$match" : {"name": "name", status : 0}},
      { "$count": "count" },
    ],
    "completed": [
      { "$match" : {"name": "name", status : 1}},
      { "$count": "count" },
    ],
    "canceled": [
      { "$match" : { "name": "name2", status : 2}},
      { "$count": "count" },
    ]
  }},

  { "$project": {
    "inProgress": { "$arrayElemAt": ["$inProgress.count", 0] },
    "completed": { "$arrayElemAt": ["$completed.count", 0] },
    "canceled": { "$arrayElemAt": ["$canceled.count", 0] }
  }}
])

2nd

Этот запрос использует индекс на этапе $ match, но, как я понимаю, структура агрегации просто выполняет агрегацию после извлечения документов из курсора, поэтому он будетвозьмите все соответствующие { name : "name" } документы и выполните итерацию по всем из них, не принимая во внимание мой пользовательский индекс (который включает в себя также информацию о статусе), для меня это звучит неэффективно.

db.reports.aggregate([
  {"$match" : {"name": "name"}},
  { "$facet": {
    "inProgress": [
      { "$match" : { status : 0 }},
      { "$count": "count" },
    ],
    "completed": [
      { "$match" : { status : 1}},
      { "$count": "count" },
    ],
    "canceled": [
      { "$match" : { status : 2}},
      { "$count": "count" },
    ]
  }},

  { "$project": {
    "inProgress": { "$arrayElemAt": ["$inProgress.count", 0] },
    "completed": { "$arrayElemAt": ["$completed.count", 0] },
    "canceled": { "$arrayElemAt": ["$canceled.count", 0] }
  }}
])

Я могуНе стоит выбирать между этими решениями, возможно, существуют и другие.Я хочу один запрос, который полностью использует мой пользовательский индекс (который включает в себя информацию о состоянии, кажется, что агрегация не использует его) и выполняет так же быстро, как и 3 отдельных запроса подсчета.Так какова лучшая практика для достижения моих целей?

...