Код: Выделить всё
{
"_id": {"$oid": "123456"},
"class": "...",
"event_data": {...},
"ts": {"$date": "2025-01-01T01:00:00.000Z"}
}
Код: Выделить всё
ZonedDateTime lowerBound = ...;
ZonedDateTime upperBound = ...;
var query = Query.query(new Criteria().andOperator(
Criteria.where("ts").gte(lowerbound.toInstant().toEpochMilli()),
Criteria.where("ts").lt(upperbound.toInstant().toEpochMilli()),
)
var result = mongoTemplate.find(query, Events.class)
Код: Выделить всё
Query: { "$and" : [{ "ts": { "$gte" : 1733852133000}}. { "ts" : { "$lt": 1733853933000}} ] }
Код: Выделить всё
db.events.find({
"$and": [
{ "ts": { "$gte": 1733852133000}},
{ "ts": { "$lt": 1733853933000}},
]
})
Однако, если я напишу следующий фрагмент, код выполнится менее чем за пару секунд:
Код: Выделить всё
db.events.find({
"$and": [
{ "ts": { "$gte": new Date("2025-01-01T01:00:00Z)}},
{ "ts": { "$lt": new Date("2025-01-02T01:00:00Z)}},
]
})
В чем основная разница между этими двумя запросами? Как я могу перевести свой Java-код во вторую версию и фактически использовать имеющуюся у нас индексацию?
Некоторые вещи, которые я пробовал:
- Используя Instant или Date вместо Long в качестве значений, они просто имеют ту же проблему, что и COLSCAN
- Добавление подсказки("ts_1") к принудительное использование индекса. При запуске этого в консоли MongoDB выдается ошибка с предоставленной подсказкой, которая не соответствует существующему индексу, что совершенно неверно, поскольку я вижу индекс при запуске .getIndexes(). Запуск его в коде Java, похоже, вызывает ту же проблему, что и раньше, когда он выполняет COLLSCAN
Вот еще несколько подробностей о том, что происходит. Сначала просто чтобы показать, что индексы существуют:
Код: Выделить всё
db.events.getIndexes();
// returns
{
"key": {
"ts": 1
},
"name": "ts_1",
"v": 2
},
{
"key": {
"ts": -1
},
"name": "ts_-1",
"v": 2
}
Код: Выделить всё
db.events.find({
"$and": [
{ "ts": { "$gte": new Date("2024-12-10T17:35:33Z")} },
{ "ts": { "$lt": new Date("2024-12-10T18:05:33Z")} }
],
}, {}, {}).explain();
// returns
{
...
"stages": [
{
"$cursor": {
"queryPlanner": {
"namespace": "database.system.buckets.events",
"indexFilterSet": false,
"parsedQuery": {
"$and": [
{
"_id": {
"$lt": {"$oid": "675882ed0000000000000000"}
}
},
{
"_id": {
"$gte": {"$oid": "67572a650000000000000000"}
}
},
{
"control.max.ts": {
"$_internalExprGte": {"$date": "2024-12-10T17:35:33.000Z"}
}
},
{
"control.min.ts": {
"$_internalExprGte": {"$date": "2024-12-09T17:35:33.000Z"}
}
},
{
"control.max.ts": {
"$_internalExprLt": {"$date": "2024-12-11T18:05:33.000Z"}
}
},
{
"control.min.ts": {
"$_internalExprLt": {"$date": "2024-12-10T18:05:33.000Z"}
}
}
]
},
...
"winningPlan": {
"stage": "FETCH",
"filter": {
"$and": [
{
"_id": {
"$lt": {"$oid": "675882ed0000000000000000"}
}
},
{
"_id": {
"$gte": {"$oid": "67572a650000000000000000"}
}
}
]
},
"inputStage": {
"stage": "IXSCAN",
"keyPattern": {
"control.min.ts": 1,
"control.max.ts": 1
},
"indexName": "ts_1",
"isMultiKey": false,
"multiKeyPaths": {
"control.min.ts": [],
"control.max.ts": []
},
"isUnique": false,
"isSparse": false,
"isPartial": false,
"indexVersion": 2,
"direction": "forward",
"indexBounds": {
"control.min.ts": ["[new Date(1733765733000), new Date(1733853933000))"],
"control.max.ts": ["[new Date(1733852133000), new Date(1733940333000))"]
}
}
}
}
Код: Выделить всё
db.events.find({
$and: [
{ ts: { $gte: 1733852133000 } },
{ ts: { $lt: 1733853933000 } }
],
}, {}, {})
// returns
{
...
"stages": [
{
"$cursor": {
"queryPlanner": {
"namespace": "db.system.buckets.events",
"indexFilterSet": false,
"parsedQuery": {
},
"queryHash": "5F5FC979",
"planCacheKey": "5F5FC979",
"maxIndexedOrSolutionsReached": false,
"maxIndexedAndSolutionsReached": false,
"maxScansToExplodeReached": false,
"winningPlan": {
"stage": "COLLSCAN",
"direction": "forward"
},
"rejectedPlans": []
}
}
},
{
"$_internalUnpackBucket": {
"exclude": [],
"timeField": "ts",
"metaField": "data",
"bucketMaxSpanSeconds": 86400,
"assumeNoMixedSchemaData": true,
"eventFilter": {
"$and": [
{
"ts": {
"$gte": 1733852133000
}
},
{
"ts": {
"$lt": 1733853933000
}
}
]
}
}
}
]
}
Код: Выделить всё
Query: { "$and" : [{ "ts" : { "$gte" : 1733852133000}}, { "ts" : { "$lt" : 1733853933000}}]}, Fields: {}, Sort: {}
Из этих поясняющих комментариев мы можем видеть большую разницу между двумя, где рабочий с new Date() добавляет дополнительную фильтрацию в столбце _id. Я предполагаю, что это как-то связано с тем, как работают коллекции временных рядов, но я не уверен. В дополнение к этому фильтры разбиваются, и перед FETCH есть этап ввода IXSCAN.
Я нашел на форуме MongoDB еще один вопрос, который очень похож, но без реального ответа на то, что происходит.. ссылка
Подробнее здесь: https://stackoverflow.com/questions/795 ... ively-long
Мобильная версия