#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
, но уверены ли вы, что они имеют какой-то эффект? Я думаю, используется только индекс ondate
? В то время, когда документ fromyoutubes
просматривается и используется в конвейере агрегирования, индексы fromyoutubes
больше не могут использоваться. Так что на самом деле вы используете только индексsort
, и после этого вы делаете все в памяти. Когда вы говорите «запрос X принимает Yms и возвращает Z» документов, то, что вы, вероятно, действительно получаете, это курсор, поэтому количество документов, которые в конечном итоге будут возвращены, может быть здесь неуместным.2. @rethab потому что я тестировал между сортировкой первым и сортировкой последним. По какой-то причине сортировка первой выполняется быстрее, чем сортировка последней (idk почему). Все используемые поля используют индекс, но
date
также являются индексом. Я обновил сообщение, чтобы включить их. Что касается курсора, то нет. Это настоящие документы. Поскольку я могу записывать их в файл одновременно. Таким образом, он извлекает все.