Я бегу MongoDB 3.0 и у меня есть коллекция, которая имеет (среди прочих) следующие показатели:
{
"v" : 1,
"key" : {
"run_state" : 1
},
"name" : "run_state_1",
"ns" : "xxx.yyyy"
},
{
"v" : 1,
"key" : {
"visibility_state" : 1
},
"name" : "visibility_state",
"ns" : "xxx.yyyy"
},
{
"v" : 1,
"key" : {
"affiliate_id" : "hashed"
},
"name" : "affiliate_id_hashed",
"ns" : "xxx.yyyy"
}
Мне нужно получить все документы, соответствующие некоторым условиям.
Одним из них является наличие поля affiliate_id
.
Если у меня есть запрос, который включает в себя $exists
оператора и другие условия, например:
db.getCollection('campaigns')
.find({
affiliate_id : { $exists : true },
visibility_state : 'showing',
run_state : 'running'
})
.explain()
я получаю следующий план выполнения:
{
"winningPlan" : {
"stage" : "KEEP_MUTATIONS",
"inputStage" : {
"stage" : "FETCH",
"filter" : {
"$and" : [
{
"visibility_state" : {
"$eq" : "showing"
}
},
{
"affiliate_id" : {
"$exists" : true
}
}
]
},
"inputStage" : {
"stage" : "IXSCAN", // GOOD, it uses the index (:
"keyPattern" : {
"run_state" : 1
},
"indexName" : "run_state_1",
"isMultiKey" : false,
"direction" : "forward",
"indexBounds" : {
"run_state" : [
"[\"running\", \"running\"]"
]
}
}
}
}
}
Таким образом, запрос будет использовать индекс и будет выполнять очень быстро.
Однако, если запрос содержит только оператор $exists
, я получаю:
{
"winningPlan" : {
"stage" : "COLLSCAN", // Full collection scan D:
"filter" : {
"affiliate_id" : {
"$exists" : true
}
},
"direction" : "forward"
},
}
Так этот запрос будет игнорировать индекс и выполнить полный сбор и сканирование будет выполнять очень плохо.
Если вместо этого я использую $ne : null
, результаты будут такими же, как указано выше.
Я понимаю, что в первом случае индекс поиск будет происходить только в run_state
поле и на следующем этапе будет просто отфильтровать неправдоподобные данные.
Мне просто интересно, почему Mongo не использует индекс для $exists
или $ne : null
.
Редактировать
Как @lascort предложил в комментариях, я изменил тип индекса быть регулярным отсортированный один. И теперь используется индекс, но он все еще имеет этот этап фильтра.
{
"winningPlan" : {
"stage" : "KEEP_MUTATIONS",
"inputStage" : {
"stage" : "FETCH",
"filter" : {
"affiliate_id" : {
"$exists" : true
}
},
"inputStage" : {
"stage" : "IXSCAN",
"keyPattern" : {
"affiliate_id" : 1.0
},
"indexName" : "affiliate_id_1",
"isMultiKey" : false,
"direction" : "forward",
"indexBounds" : {
"affiliate_id" : [
"[MinKey, MaxKey]"
]
}
}
}
},
}
Я также создал индекс соединения с run_state
, visibility_state
и affiliate_id
клавиш, сохраняя при этом отдельные из них. Если я выполнить запрос, содержащий 3 поля, я получаю то же самое, прежде чем создавать составной индекс, с FETCH стадии, содержащей операцию ФИЛЬТР:
{
"winningPlan" : {
"stage" : "KEEP_MUTATIONS",
"inputStage" : {
"stage" : "FETCH",
"filter" : {
"$and" : [
{
"visibility_state" : {
"$eq" : "showing"
}
},
{
"affiliate_id" : {
"$exists" : true
}
}
]
},
"inputStage" : {
"stage" : "IXSCAN",
"keyPattern" : {
"run_state" : 1.0
},
"indexName" : "run_state_1",
"isMultiKey" : false,
"direction" : "forward",
"indexBounds" : {
"run_state" : [
"[\"running\", \"running\"]"
]
}
}
}
}
},
Если я падение 3 односпальных индексов, то я получаю это:
{
"winningPlan" : {
"stage" : "KEEP_MUTATIONS",
"inputStage" : {
"stage" : "FETCH",
"filter" : {
"affiliate_id" : {
"$exists" : true
}
},
"inputStage" : {
"stage" : "IXSCAN",
"keyPattern" : {
"visibility_state" : 1.0,
"run_state" : 1.0,
"affiliate_id" : 1.0
},
"indexName" : "visibility_state_1_run_state_1_affiliate_id_1",
"isMultiKey" : false,
"direction" : "forward",
"indexBounds" : {
"visibility_state" : [
"[\"showing\", \"showing\"]"
],
"run_state" : [
"[\"running\", \"running\"]"
],
"affiliate_id" : [
"[MinKey, MaxKey]"
]
}
}
}
}
}
Который кажется более эффективным.
Я не совсем уверен, что происходит, как и почему он не будет использовать индекс, но это, кажется, проблема с индекс 'affiliate_id'« hashed ». Если вы создадите обычный индекс, он будет работать нормально. По другому вопросу .. для вашего первого запроса вы должны рассмотреть использование составного индекса, он должен работать лучше, чем только с использованием индекса run_state. А для вашего второго запроса (единственного с условием '$ exists: true') разреженный индекс звучит хорошо. – lascort
Спасибо @ lascort, регулярный индекс сделал это!: D О составных индексах, должен ли я создать новый или рассмотреть вопрос о слиянии этого 3 в 1? Каковы предельные накладные расходы на добавление нового индекса в монго? –