Несогласованный агрегированный вызов MongoDB между запросами

#mongodb #mongodb-query #aggregation-framework #mongodb-indexes

#mongodb #mongodb-запрос #агрегация-фреймворк #mongodb-индексы

Вопрос:

У меня есть две таблицы. videos и youtubes . Я хочу сделать $lookup вкл videos.youtube и сопоставить это с youtubes._id , а затем $match с этими данными на основе youtubes поля. Который работает нормально, но есть некоторые огромные несоответствия между запросами, которые должны быть идентичны по своей природе или, по крайней мере, близки к этому.

Запрос 1: возвращает 8261 документ. Для выполнения требуется [40, 50] мс

 db.getCollection('videos').aggregate([
  { '$sort': { date: -1 } },
  {
    '$lookup': {
      from: 'youtubes',
      localField: 'youtube',
      foreignField: '_id',
      as: 'youtube'
    }
  },
  { '$match': { 'youtube.talent': true } },
])
 

Запрос 2: возвращает 760 документов. Для выполнения требуется [470, 500] мс

 db.getCollection('videos').aggregate([
  { '$sort': { date: -1 } },
  {
    '$lookup': {
      from: 'youtubes',
      localField: 'youtube',
      foreignField: '_id',
      as: 'youtube'
    }
  },
  { '$match': { 'youtube.id': 7 } },
])
 

Запрос 3: возвращает 760 документов. Для выполнения требуется [90, 100] мс

 db.getCollection('videos').aggregate([
  // { '$sort': { date: -1 } },
  {
    '$lookup': {
      from: 'youtubes',
      localField: 'youtube',
      foreignField: '_id',
      as: 'youtube'
    }
  },
  { '$match': { 'youtube.id': 7 } },
])
 

Все поля, используемые в запросах, индексируются. Что выделяется, так это то, что $sort оператор в запросе 2, по-видимому, использует примерно 400 мс для выполнения, но в запросе 1 используется тот же $sort оператор в том же месте в конвейере, и он использует только [40, 50] мс.

Я использовал эту { explain: true } опцию для поиска различий между запросом 1 и запросом 2, которые могли бы объяснить различия в скорости, но они идентичны, за исключением $match части.

Любое решение / предложения по ускорению выполнения запроса 2 с помощью запроса 1? Или, по крайней мере, объяснение огромных различий в скорости?


Еще одна странная вещь, обнаруженная при создании этого сообщения

Запрос 4: возвращает 9378 документов. Для выполнения требуется [25, 35] мс

 db.getCollection('videos').aggregate([
  { '$sort': { date: -1 } },
  {
    '$lookup': {
      from: 'youtubes',
      localField: 'youtube',
      foreignField: '_id',
      as: 'youtube'
    }
  },
  { '$match': { 'youtube.clipper': true } }
])
 

Query 5: returns 9378 documents. Takes [600, 680]ms to execute

 db.getCollection('videos').aggregate([
  //{ '$sort': { date: -1 } },
  {
    '$lookup': {
      from: 'youtubes',
      localField: 'youtube',
      foreignField: '_id',
      as: 'youtube'
    }
  },
  { '$match': { 'youtube.clipper': true } }
])
 

At this point I’m stumped as to what is happening. Originally I thought it had to do with Number vs Boolean, but as Query 4 and Query 5 shows it clearly has 0 impact. And it seems random.

Indexes just in case (for youtubes )

 [
    {
        "v" : 2,
        "key" : {
            "_id" : 1
        },
        "name" : "_id_",
        "ns" : "holo-watcher.youtubes"
    },
    {
        "v" : 2,
        "unique" : true,
        "key" : {
            "id" : 1
        },
        "name" : "id_1",
        "ns" : "holo-watcher.youtubes",
        "background" : true
    },
    {
        "v" : 2,
        "key" : {
            "name" : 1
        },
        "name" : "name_1",
        "ns" : "holo-watcher.youtubes",
        "background" : true
    },
    {
        "v" : 2,
        "unique" : true,
        "key" : {
            "channelId" : 1
        },
        "name" : "channelId_1",
        "ns" : "holo-watcher.youtubes",
        "background" : true
    },
    {
        "v" : 2,
        "key" : {
            "clipper" : 1
        },
        "name" : "clipper_1",
        "ns" : "holo-watcher.youtubes",
        "background" : true
    },
    {
        "v" : 2,
        "key" : {
            "talent" : 1
        },
        "name" : "talent_1",
        "ns" : "holo-watcher.youtubes",
        "background" : true
    },
    {
        "v" : 2,
        "key" : {
            "debut" : 1
        },
        "name" : "debut_1",
        "ns" : "holo-watcher.youtubes",
        "background" : true
    }
]
 

indexes (for videos )

 [
    {
        "v" : 2,
        "key" : {
            "_id" : 1
        },
        "name" : "_id_",
        "ns" : "holo-watcher.videos"
    },
    {
        "v" : 2,
        "unique" : true,
        "key" : {
            "videoId" : 1
        },
        "name" : "videoId_1",
        "ns" : "holo-watcher.videos",
        "background" : true
    },
    {
        "v" : 2,
        "key" : {
            "title" : 1
        },
        "name" : "title_1",
        "ns" : "holo-watcher.videos",
        "background" : true
    },
    {
        "v" : 2,
        "key" : {
            "date" : 1
        },
        "name" : "date_1",
        "ns" : "holo-watcher.videos",
        "background" : true
    }
]
 

{ explain: true } вывод для запроса 5 (почти идентичен запросу 1 и запросу 2):

 {
    "stages" : [ 
        {
            "$cursor" : {
                "query" : {},
                "sort" : {
                    "date" : -1
                },
                "queryPlanner" : {
                    "plannerVersion" : 1,
                    "namespace" : "holo-watcher.videos",
                    "indexFilterSet" : false,
                    "parsedQuery" : {},
                    "winningPlan" : {
                        "stage" : "FETCH",
                        "inputStage" : {
                            "stage" : "IXSCAN",
                            "keyPattern" : {
                                "date" : 1
                            },
                            "indexName" : "date_1",
                            "isMultiKey" : false,
                            "multiKeyPaths" : {
                                "date" : []
                            },
                            "isUnique" : false,
                            "isSparse" : false,
                            "isPartial" : false,
                            "indexVersion" : 2,
                            "direction" : "backward",
                            "indexBounds" : {
                                "date" : [ 
                                    "[MaxKey, MinKey]"
                                ]
                            }
                        }
                    },
                    "rejectedPlans" : []
                }
            }
        }, 
        {
            "$lookup" : {
                "from" : "youtubes",
                "as" : "youtube",
                "localField" : "youtube",
                "foreignField" : "_id"
            }
        }, 
        {
            "$match" : {
                "youtube.clipper" : {
                    "$eq" : true
                }
            }
        }
    ],
    "ok" : 1.0
}
 

Комментарии:

1. Почему вы сначала сортируете по date ? Вы показываете индексы включенными youtubes , но уверены ли вы, что они имеют какой-то эффект? Я думаю, используется только индекс on date ? В то время, когда документ from youtubes просматривается и используется в конвейере агрегирования, индексы from youtubes больше не могут использоваться. Так что на самом деле вы используете только индекс sort , и после этого вы делаете все в памяти. Когда вы говорите «запрос X принимает Yms и возвращает Z» документов, то, что вы, вероятно, действительно получаете, это курсор, поэтому количество документов, которые в конечном итоге будут возвращены, может быть здесь неуместным.

2. @rethab потому что я тестировал между сортировкой первым и сортировкой последним. По какой-то причине сортировка первой выполняется быстрее, чем сортировка последней (idk почему). Все используемые поля используют индекс, но date также являются индексом. Я обновил сообщение, чтобы включить их. Что касается курсора, то нет. Это настоящие документы. Поскольку я могу записывать их в файл одновременно. Таким образом, он извлекает все.