Mongodb использует неправильный индекс
У меня есть несколько индексов для коллекции следующим образом. В частности, я хочу использовать запрос "gTs_1_RE_H_1_l_1"
, но запрос использует "gTs_1"
вместо!
{
"0" : {
"v" : 1,
"key" : {
"_id" : 1
},
"ns" : "week_raw_tweet_db.tweets",
"name" : "_id_"
},
"1" : {
"v" : 1,
"key" : {
"gTs" : 1
},
"ns" : "week_raw_tweet_db.tweets",
"name" : "gTs_1",
"expireAfterSeconds" : 604800
},
"2" : {
"v" : 1,
"key" : {
"uN" : 1
},
"ns" : "week_raw_tweet_db.tweets",
"name" : "uN_1"
},
"3" : {
"v" : 1,
"key" : {
"gTs" : 1,
"RE_H" : 1,
"l" : 1
},
"ns" : "week_raw_tweet_db.tweets",
"name" : "gTs_1_RE_H_1_l_1",
"background" : 1
}
}
Здесь у меня есть индекс наgTs
"один (основанный на TTL индекс) и составной индекс с"gTs
' а также 'RE_H
'как первые два ключа. ("gTs_1_RE_H_1_l_1"
)
Теперь я пытаюсь выполнить этот запрос:
db.tweets.find( {
"RE_H" : NumberLong("484001755192636620"),
"gTs" : {
"$lte" : ISODate("2014-03-18T22:00:00Z"),
"$gte" : ISODate("2014-03-17T21:00:00Z")
}
}).explain()
Это должно, насколько мне известно, использовать "gTs_1_RE_H_1_l_1"
, но на удивление он использует, "gTs_1"
как указано в этом выводе:
{
"cursor" : "BtreeCursor gTs_1",
"isMultiKey" : false,
"n" : 46508,
"nscannedObjects" : 365746,
"nscanned" : 365746,
"nscannedObjectsAllPlans" : 370493,
"nscannedAllPlans" : 370494,
"scanAndOrder" : false,
"indexOnly" : false,
"nYields" : 1,
"nChunkSkips" : 0,
"millis" : 1509,
"indexBounds" : {
"gTs" : [
[
ISODate("2014-03-17T21:00:00.000Z"),
ISODate("2014-03-18T22:00:00.000Z")
]
]
},
"server" : "Frrole-API1:27017"
}
Как бы то ни было, если я дам подсказку, она подберет правильный индекс. Итак, если я запускаю следующий запрос:
db.tweets.find( {
"RE_H" : NumberLong("484001755192636620"),
"gTs" : {
"$lte" : ISODate("2014-03-18T22:00:00Z"),
"$gte" : ISODate("2014-03-17T21:00:00Z")
}
}).hint("gTs_1_RE_H_1_l_1").explain()
Я получаю следующий вывод:
/* 0 */
{
"cursor" : "BtreeCursor gTs_1_RE_H_1_l_1",
"isMultiKey" : true,
"n" : 46508,
"nscannedObjects" : 233224,
"nscanned" : 233541,
"nscannedObjectsAllPlans" : 233224,
"nscannedAllPlans" : 233541,
"scanAndOrder" : false,
"indexOnly" : false,
"nYields" : 3,
"nChunkSkips" : 0,
"millis" : 1874,
"indexBounds" : {
"gTs" : [
[
true,
ISODate("2014-03-18T22:00:00.000Z")
]
],
"RE_H" : [
[
NumberLong(484001755192636620),
NumberLong(484001755192636620)
]
],
"l" : [
[
{
"$minElement" : 1
},
{
"$maxElement" : 1
}
]
]
},
"server" : "Frrole-API1:27017"
}
Может кто-нибудь, пожалуйста, помогите мне понять, что происходит!
2 ответа
Как видно из результатов, запрос, использующий более простой индекс, быстрее примерно на 300 мс, поэтому mongodb использует этот индекс. Оптимизация MongoDB не пытается понять путь запроса и угадать, насколько он будет быстрым, он просто выполняет различные запросы и измеряет, какой из них самый быстрый. Ваш MongoDB узнал, что быстрее, используя простой gTs
индекс. Он будет автоматически проверять это время от времени, параллельно выполняя различные запросы.
Это должно, насколько мне известно, использовать "gTs_1_RE_H_1_l_1", но, как ни удивительно, он использует "gTs_1", как указано в этих выходных данных:
Это не удивительно. Вам следует ознакомиться с документацией по индексации, в частности с разделом о сортировке. Хотя вы не запрашиваете сортировку здесь, вы используете запрос диапазона ($lte
и его братья и сестры), что очень похоже. Вам, по крайней мере, нужно изменить порядок индексов на RE_H
, gTs
так, что сначала идет индекс для ограничения equals, а затем запрос диапазона.
Кажется, что порядок определения индексов также эффективен при его выборе, например:
{
"0" : {
"v" : 1,
"key" : {
"_id" : 1
},
"ns" : "week_raw_tweet_db.tweets",
"name" : "_id_"
},
"1" : {
"v" : 1,
"key" : {
"gTs" : 1,
"RE_H" : 1,
"l" : 1
},
"ns" : "week_raw_tweet_db.tweets",
"name" : "gTs_1_RE_H_1_l_1",
"background" : 1
},
"2" : {
"v" : 1,
"key" : {
"gTs" : 1
},
"ns" : "week_raw_tweet_db.tweets",
"name" : "gTs_1",
"expireAfterSeconds" : 604800
},
"3" : {
"v" : 1,
"key" : {
"uN" : 1
},
"ns" : "week_raw_tweet_db.tweets",
"name" : "uN_1"
}
}