MongoDB not using index when sorting - mongodb

I'm using mongo 4.0.12 and I'm trying to tune my most executed query:
db.getCollection('ServiceInvoice').find(
{
"Provider.ParentId": "60f9d7631b1f243eb82903ee",
"Provider._id": "60f9d803fa27e34fdc4ec159",
"Environment": 1,
"Status": 2,
"IssuedOn":
{
"$gte": { DateTime: new Date("2022-02-01T00:00:00Z") },
"$lte": { DateTime: new Date("2022-02-01T23:59:59Z") }
}
}).limit(50).skip(1050).sort({ "IssueOn.DateTime": -1 })
using an index like:
{
"Environment" : 1.0,
"Provider.ParentId" : 1.0,
"Provider._id" : 1.0,
"Status" : 1.0,
"IssuedOn" : 1.0,
"IssuedOn.DateTime" : -1.0
}
and gives me this explain:
{
"queryPlanner" : {
"plannerVersion" : 1,
"namespace" : "test.ServiceInvoice",
"indexFilterSet" : false,
"parsedQuery" : {
"$and" : [
{
"Environment" : {
"$eq" : 1.0
}
},
{
"Provider.ParentId" : {
"$eq" : "60f9d7631b1f243eb82903ee"
}
},
{
"Provider._id" : {
"$eq" : "60f9d803fa27e34fdc4ec159"
}
},
{
"Status" : {
"$eq" : 2.0
}
},
{
"IssuedOn" : {
"$lte" : {
"DateTime" : ISODate("2022-02-01T23:59:59.000Z")
}
}
},
{
"IssuedOn" : {
"$gte" : {
"DateTime" : ISODate("2022-02-01T00:00:00.000Z")
}
}
}
]
},
"winningPlan" : {
"stage" : "SKIP",
"skipAmount" : 0,
"inputStage" : {
"stage" : "SORT",
"sortPattern" : {
"IssueOn.DateTime" : -1.0
},
"limitAmount" : 1100,
"inputStage" : {
"stage" : "SORT_KEY_GENERATOR",
"inputStage" : {
"stage" : "FETCH",
"inputStage" : {
"stage" : "IXSCAN",
"keyPattern" : {
"Environment" : 1.0,
"Provider.ParentId" : 1.0,
"Provider._id" : 1.0,
"Status" : 1.0,
"IssuedOn" : 1.0,
"IssuedOn.DateTime" : -1.0
},
"indexName" : "Environment_1_Provider.ParentId_1_Provider._id_1_Status_1_IssueOn_1_IssueOn.DateTime_-1",
"isMultiKey" : false,
"multiKeyPaths" : {
"Environment" : [],
"Provider.ParentId" : [],
"Provider._id" : [],
"Status" : [],
"IssuedOn" : [],
"IssuedOn.DateTime" : []
},
"isUnique" : false,
"isSparse" : false,
"isPartial" : false,
"indexVersion" : 2,
"direction" : "forward",
"indexBounds" : {
"Environment" : [
"[1.0, 1.0]"
],
"Provider.ParentId" : [
"[\"60f9d7631b1f243eb82903ee\", \"60f9d7631b1f243eb82903ee\"]"
],
"Provider._id" : [
"[\"60f9d803fa27e34fdc4ec159\", \"60f9d803fa27e34fdc4ec159\"]"
],
"Status" : [
"[2.0, 2.0]"
],
"IssuedOn" : [
"[{ DateTime: new Date(1643673600000) }, { DateTime: new Date(1643759999000) }]"
],
"IssuedOn.DateTime" : [
"[MaxKey, MinKey]"
]
}
}
}
}
}
},
"rejectedPlans" : []
},
"executionStats" : {
"executionSuccess" : true,
"nReturned" : 50,
"executionTimeMillis" : 99,
"totalKeysExamined" : 31622,
"totalDocsExamined" : 31622,
"executionStages" : {
"stage" : "SKIP",
"nReturned" : 50,
"executionTimeMillisEstimate" : 6,
"works" : 32725,
"advanced" : 50,
"needTime" : 32674,
"needYield" : 0,
"saveState" : 255,
"restoreState" : 255,
"isEOF" : 1,
"invalidates" : 0,
"skipAmount" : 0,
"inputStage" : {
"stage" : "SORT",
"nReturned" : 1100,
"executionTimeMillisEstimate" : 6,
"works" : 32725,
"advanced" : 1100,
"needTime" : 31624,
"needYield" : 0,
"saveState" : 255,
"restoreState" : 255,
"isEOF" : 1,
"invalidates" : 0,
"sortPattern" : {
"IssueOn.DateTime" : -1.0
},
"memUsage" : 3057213,
"memLimit" : 33554432,
"limitAmount" : 1100,
"inputStage" : {
"stage" : "SORT_KEY_GENERATOR",
"nReturned" : 31622,
"executionTimeMillisEstimate" : 4,
"works" : 31624,
"advanced" : 31622,
"needTime" : 1,
"needYield" : 0,
"saveState" : 255,
"restoreState" : 255,
"isEOF" : 1,
"invalidates" : 0,
"inputStage" : {
"stage" : "FETCH",
"nReturned" : 31622,
"executionTimeMillisEstimate" : 3,
"works" : 31623,
"advanced" : 31622,
"needTime" : 0,
"needYield" : 0,
"saveState" : 255,
"restoreState" : 255,
"isEOF" : 1,
"invalidates" : 0,
"docsExamined" : 31622,
"alreadyHasObj" : 0,
"inputStage" : {
"stage" : "IXSCAN",
"nReturned" : 31622,
"executionTimeMillisEstimate" : 1,
"works" : 31623,
"advanced" : 31622,
"needTime" : 0,
"needYield" : 0,
"saveState" : 255,
"restoreState" : 255,
"isEOF" : 1,
"invalidates" : 0,
"keyPattern" : {
"Environment" : 1.0,
"Provider.ParentId" : 1.0,
"Provider._id" : 1.0,
"Status" : 1.0,
"IssuedOn" : 1.0,
"IssuedOn.DateTime" : -1.0
},
"indexName" : "Environment_1_Provider.ParentId_1_Provider._id_1_Status_1_IssueOn_1_IssueOn.DateTime_-1",
"isMultiKey" : false,
"multiKeyPaths" : {
"Environment" : [],
"Provider.ParentId" : [],
"Provider._id" : [],
"Status" : [],
"IssuedOn" : [],
"IssuedOn.DateTime" : []
},
"isUnique" : false,
"isSparse" : false,
"isPartial" : false,
"indexVersion" : 2,
"direction" : "forward",
"indexBounds" : {
"Environment" : [
"[1.0, 1.0]"
],
"Provider.ParentId" : [
"[\"60f9d7631b1f243eb82903ee\", \"60f9d7631b1f243eb82903ee\"]"
],
"Provider._id" : [
"[\"60f9d803fa27e34fdc4ec159\", \"60f9d803fa27e34fdc4ec159\"]"
],
"Status" : [
"[2.0, 2.0]"
],
"IssuedOn" : [
"[{ DateTime: new Date(1643673600000) }, { DateTime: new Date(1643759999000) }]"
],
"IssuedOn.DateTime" : [
"[MaxKey, MinKey]"
]
},
"keysExamined" : 31622,
"seeks" : 1,
"dupsTested" : 0,
"dupsDropped" : 0,
"seenInvalidated" : 0
}
}
}
}
},
"allPlansExecution" : []
},
"serverInfo" : {
"host" : "d4ef6b3e9c6c",
"port" : 27017,
"version" : "4.0.12",
"gitVersion" : "5776e3cbf9e7afe86e6b29e22520ffb6766e95d4"
},
"ok" : 1.0
}
However, dbKoda keeps me saying that I must create an index for sorting.
I've already tried to create a separated index for IssuedOn.DateTime, but it keeps me recommending the creation and I don't see any effects.
How can I solve this problem? (Changes to the document fields are not an option).

According to these threads - MongoDB - Index not being used when sorting and limiting on ranged query and https://emptysqua.re/blog/optimizing-mongodb-compound-indexes/
A compund Index should be created following this order:
Equality Tests: Add all equality-tested fields to the compound index, in any order;
Sort Fields (ascending / descending only matters if there are multiple sort fields): Add sort fields to the index in the same order and direction as your query's sort;
Range Filters: First, add the range filter for the field with the lowest cardinality (fewest distinct values in the collection). Then the next lowest-cardinality range filter, and so on to the highest-cardinality.
So, the solution was creating an index like this:
{
"Environment" : 1.0,
"Provider.ParentId" : 1.0,
"Provider._id" : 1.0,
"Status" : 1.0,
"IssuedOn.DateTime" : -1.0,
"IssuedOn" : 1.0
}
And now, the query uses the index for sorting and fetch only the records in range.

Related

mongodb query slow in different version and env

I have two env mongodbs,
the difference between them is:
test mongodb version: 3.2.20 , prod mongodb version : 4.0.18
and test env query plan first stage is Limit , however the other is Sort.
in my test env, it's very quick and totalDocsExamined == limit
they both hit the index:
{
"v" : 1,
"key" : {
"appIds" : 1,
"ctime" : -1,
"background" : 1
},
"name" : "appIds_1_ctime_-1_background_1",
"ns" : "newsmine.newstoapp"
}
query: db.newstoapp.find({"appIds":{"$in":[999]}}).sort({"ctime":-1}).limit(10).explain('executionStats')
{
"queryPlanner" : {
"plannerVersion" : 1,
"namespace" : "newsmine.newstoapp",
"indexFilterSet" : false,
"parsedQuery" : {
"appIds" : {
"$in" : [
999
]
}
},
"winningPlan" : {
"stage" : "LIMIT",
"limitAmount" : 10,
"inputStage" : {
"stage" : "FETCH",
"inputStage" : {
"stage" : "IXSCAN",
"keyPattern" : {
"appIds" : 1,
"ctime" : -1,
"background" : 1
},
"indexName" : "appIds_1_ctime_-1_background_1",
"isMultiKey" : true,
"isUnique" : false,
"isSparse" : false,
"isPartial" : false,
"indexVersion" : 1,
"direction" : "forward",
"indexBounds" : {
"appIds" : [
"[999.0, 999.0]"
],
"ctime" : [
"[MaxKey, MinKey]"
],
"background" : [
"[MinKey, MaxKey]"
]
}
}
}
},
"rejectedPlans" : [ ]
},
"executionStats" : {
"executionSuccess" : true,
"nReturned" : 10,
"executionTimeMillis" : 0,
"totalKeysExamined" : 10,
"totalDocsExamined" : 10,
"executionStages" : {
"stage" : "LIMIT",
"nReturned" : 10,
"executionTimeMillisEstimate" : 0,
"works" : 11,
"advanced" : 10,
"needTime" : 0,
"needYield" : 0,
"saveState" : 0,
"restoreState" : 0,
"isEOF" : 1,
"invalidates" : 0,
"limitAmount" : 10,
"inputStage" : {
"stage" : "FETCH",
"nReturned" : 10,
"executionTimeMillisEstimate" : 0,
"works" : 10,
"advanced" : 10,
"needTime" : 0,
"needYield" : 0,
"saveState" : 0,
"restoreState" : 0,
"isEOF" : 0,
"invalidates" : 0,
"docsExamined" : 10,
"alreadyHasObj" : 0,
"inputStage" : {
"stage" : "IXSCAN",
"nReturned" : 10,
"executionTimeMillisEstimate" : 0,
"works" : 10,
"advanced" : 10,
"needTime" : 0,
"needYield" : 0,
"saveState" : 0,
"restoreState" : 0,
"isEOF" : 0,
"invalidates" : 0,
"keyPattern" : {
"appIds" : 1,
"ctime" : -1,
"background" : 1
},
"indexName" : "appIds_1_ctime_-1_background_1",
"isMultiKey" : true,
"isUnique" : false,
"isSparse" : false,
"isPartial" : false,
"indexVersion" : 1,
"direction" : "forward",
"indexBounds" : {
"appIds" : [
"[999.0, 999.0]"
],
"ctime" : [
"[MaxKey, MinKey]"
],
"background" : [
"[MinKey, MaxKey]"
]
},
"keysExamined" : 10,
"dupsTested" : 10,
"dupsDropped" : 0,
"seenInvalidated" : 0
}
}
}
},
"serverInfo" : {
"host" : "",
"port" : ,
"version" : "3.2.20",
"gitVersion" : "a7a144f40b70bfe290906eb33ff2714933544af8"
},
"ok" : 1
}
in my prod env, it's getting slow query
query: datamongo:PRIMARY> db.newstoapp.find({"appIds":{"$in":[1460]}}).sort({"ctime":-1}).limit(10).explain('executionStats')
{
"queryPlanner" : {
"plannerVersion" : 1,
"namespace" : "newsmine.newstoapp",
"indexFilterSet" : false,
"parsedQuery" : {
"appIds" : {
"$eq" : 1460
}
},
"winningPlan" : {
"stage" : "SORT",
"sortPattern" : {
"ctime" : -1
},
"limitAmount" : 10,
"inputStage" : {
"stage" : "SORT_KEY_GENERATOR",
"inputStage" : {
"stage" : "FETCH",
"inputStage" : {
"stage" : "IXSCAN",
"keyPattern" : {
"appIds" : 1,
"ctime" : -1,
"background" : 1
},
"indexName" : "appIds_1_ctime_-1_background_1",
"isMultiKey" : true,
"isUnique" : false,
"isSparse" : false,
"isPartial" : false,
"indexVersion" : 1,
"direction" : "forward",
"indexBounds" : {
"appIds" : [
"[1460.0, 1460.0]"
],
"ctime" : [
"[MaxKey, MinKey]"
],
"background" : [
"[MinKey, MaxKey]"
]
}
}
}
}
},
"rejectedPlans" : [
{
"stage" : "SORT",
"sortPattern" : {
"ctime" : -1
},
"limitAmount" : 10,
"inputStage" : {
"stage" : "SORT_KEY_GENERATOR",
"inputStage" : {
"stage" : "FETCH",
"inputStage" : {
"stage" : "IXSCAN",
"keyPattern" : {
"appIds" : 1
},
"indexName" : "appIds_1",
"isMultiKey" : true,
"isUnique" : false,
"isSparse" : false,
"isPartial" : false,
"indexVersion" : 1,
"direction" : "forward",
"indexBounds" : {
"appIds" : [
"[1460.0, 1460.0]"
]
}
}
}
}
},
{
"stage" : "LIMIT",
"limitAmount" : 10,
"inputStage" : {
"stage" : "FETCH",
"filter" : {
"appIds" : {
"$eq" : 1460
}
},
"inputStage" : {
"stage" : "IXSCAN",
"keyPattern" : {
"ctime" : 1
},
"indexName" : "ctime_1",
"isMultiKey" : false,
"isUnique" : false,
"isSparse" : false,
"isPartial" : false,
"indexVersion" : 1,
"direction" : "backward",
"indexBounds" : {
"ctime" : [
"[MaxKey, MinKey]"
]
}
}
}
}
]
},
"executionStats" : {
"executionSuccess" : true,
"nReturned" : 10,
"executionTimeMillis" : 40,
"totalKeysExamined" : 405,
"totalDocsExamined" : 405,
"executionStages" : {
"stage" : "SORT",
"nReturned" : 10,
"executionTimeMillisEstimate" : 3,
"works" : 418,
"advanced" : 10,
"needTime" : 407,
"needYield" : 0,
"saveState" : 9,
"restoreState" : 9,
"isEOF" : 1,
"invalidates" : 0,
"sortPattern" : {
"ctime" : -1
},
"memUsage" : 8471,
"memLimit" : 33554432,
"limitAmount" : 10,
"inputStage" : {
"stage" : "SORT_KEY_GENERATOR",
"nReturned" : 405,
"executionTimeMillisEstimate" : 3,
"works" : 407,
"advanced" : 405,
"needTime" : 1,
"needYield" : 0,
"saveState" : 9,
"restoreState" : 9,
"isEOF" : 1,
"invalidates" : 0,
"inputStage" : {
"stage" : "FETCH",
"nReturned" : 405,
"executionTimeMillisEstimate" : 3,
"works" : 406,
"advanced" : 405,
"needTime" : 0,
"needYield" : 0,
"saveState" : 9,
"restoreState" : 9,
"isEOF" : 1,
"invalidates" : 0,
"docsExamined" : 405,
"alreadyHasObj" : 0,
"inputStage" : {
"stage" : "IXSCAN",
"nReturned" : 405,
"executionTimeMillisEstimate" : 1,
"works" : 406,
"advanced" : 405,
"needTime" : 0,
"needYield" : 0,
"saveState" : 9,
"restoreState" : 9,
"isEOF" : 1,
"invalidates" : 0,
"keyPattern" : {
"appIds" : 1,
"ctime" : -1,
"background" : 1
},
"indexName" : "appIds_1_ctime_-1_background_1",
"isMultiKey" : true,
"isUnique" : false,
"isSparse" : false,
"isPartial" : false,
"indexVersion" : 1,
"direction" : "forward",
"indexBounds" : {
"appIds" : [
"[1460.0, 1460.0]"
],
"ctime" : [
"[MaxKey, MinKey]"
],
"background" : [
"[MinKey, MaxKey]"
]
},
"keysExamined" : 405,
"seeks" : 1,
"dupsTested" : 405,
"dupsDropped" : 0,
"seenInvalidated" : 0
}
}
}
}
},
"serverInfo" : {
"host" : "",
"port" : ,
"version" : "4.0.18",
"gitVersion" : "6883bdfb8b8cff32176b1fd176df04da9165fd67"
},
"ok" : 1,
"operationTime" : Timestamp(1629988625, 146),
"$clusterTime" : {
"clusterTime" : Timestamp(1629988625, 146),
"signature" : {
"hash" : BinData(0,"AAAAAAAAAAAAAAAAAAAAAAAAAAA="),
"keyId" : NumberLong(0)
}
}
}
i followed Joe, changed my index, ctime before appIds.
but it does not work very well. there still be slow log for my new sql. it's hard to find out why it is slow
2021-10-19T22:38:16.918+0800 I COMMAND [conn2434281164] command newsmine.newstoapp command: find { find: "newstoapp", filter: { appIds: { $elemMatch: { $in: [ 2433 ] } }, ctime: { $gte: 0 } }, sort: { ctime: -1 }, hint: { ctime: -1, appIds: 1 }, skip: 0, limit: 50, batchSize: 50, $readPreference: { mode: "secondaryPreferred" }, $db: "newsmine" } planSummary: IXSCAN { ctime: -1, appIds: 1 } keysExamined:1471582 docsExamined:50 cursorExhausted:1 numYields:11496 nreturned:50 reslen:34043 locks:{ Global: { acquireCount: { r: 11497 } }, Database: { acquireCount: { r: 11497 } }, Collection: { acquireCount: { r: 11497 } } } storage:{ data: { bytesRead: 44958, timeReadingMicros: 618 } } protocol:op_query 7038ms
The cause of the slowness is that MongoDB 4.0.18 hash a blocking sort stage, so all matching documents must be found, retrieved, and sorted in memory before returning the requested batch.
In prior versions of MongoDB it was found that under certain conditions using a multi-key index to support a sort would provide incorrect result.
I never fully understood these conditions or why the results were incorrect, so if you are able to find those details, please edit or comment.
Prior to MongoDB 3.4 the index metadata contained a boolean value to indicate whether or not the index was multi-key (indexed a field that contained an array for at least one document).
MongoDB 3.4 introduced a new index version that also keeps track of which fields in the index are multi-key.
MongoDB 3.6 introduced a change to sorting to avoid the situations where results would be incorrect. This is why your query has a sort stage and is taking longer.
There are a couple things you could try to get back to the previous behavior without a blocking sort:
Drop and rebuild the index.
The existing index is version 1, which does not track multi-key paths. When rebuilding, the index should be created at version 2, which does track these, and may permit the query executor to use the index for sorting.
Create a new index with ctime before appIds.
A multi-key index has an entry in the index for each value in the indexed array. This may cause the query planner to assume it will disrupt sorting on a following key.
An index on {ctime:-1, appIds:1, background:1} would place the sort key ahead of the multi-key field, and while this may require reading more of the index, it may also permit the query executor to use the index for sorting.

mongodb 3.2.7 sorting not using compound index

I'm using mongodb 3.2.7, docs like:
{
"finished" : true,
"buildNo": 1,
"tryTimes" : 1,
"createdTime" : ISODate("2019-05-16T19:00:50.604+08:00"),
"modifiedTime" : ISODate("2019-12-27T18:33:25.682+08:00"),
}
I created my index using:
db.getCollection('builds').createIndex({"createdTime": 1})
db.getCollection('builds').createIndex({"tryTimes": 1, "createdTime": -1})
and my query is :
db.getCollection('builds').find({
"createdTime": {$lte: new Date("2020-04-15T00:00:00.000Z"), $gte: new Date("2020-04-01T00:00:00.000Z")},
"buildNo": 1,
"finished": {$ne: true}
})
.sort({"tryTimes": 1, "createdTime": -1})
.limit(200)
But this query doesn't use the index I created before. the explain() output:
{
"queryPlanner" : {
"plannerVersion" : 1,
"namespace" : "builds",
"indexFilterSet" : false,
"parsedQuery" : {
"$and" : [
{
"buildNo" : {
"$eq" : 1.0
}
},
{
"createdTime" : {
"$lte" : ISODate("2020-04-15T08:00:00.000+08:00")
}
},
{
"createdTime" : {
"$gte" : ISODate("2020-04-01T08:00:00.000+08:00")
}
},
{
"$not" : {
"finished" : {
"$eq" : true
}
}
}
]
},
"winningPlan" : {
"stage" : "SORT",
"sortPattern" : {
"tryTimes" : 1.0,
"createdTime" : -1.0
},
"limitAmount" : 200,
"inputStage" : {
"stage" : "SORT_KEY_GENERATOR",
"inputStage" : {
"stage" : "FETCH",
"filter" : {
"$and" : [
{
"buildNo" : {
"$eq" : 1.0
}
},
{
"$not" : {
"finished" : {
"$eq" : true
}
}
}
]
},
"inputStage" : {
"stage" : "IXSCAN",
"keyPattern" : {
"createdTime" : 1.0
},
"indexName" : "createdTime_1",
"isMultiKey" : false,
"isUnique" : false,
"isSparse" : false,
"isPartial" : false,
"indexVersion" : 1,
"direction" : "forward",
"indexBounds" : {
"createdTime" : [
"[new Date(1585699200000), new Date(1586908800000)]"
]
}
}
}
}
},
"rejectedPlans" : [
{
"stage" : "LIMIT",
"limitAmount" : 200,
"inputStage" : {
"stage" : "FETCH",
"filter" : {
"$and" : [
{
"buildNo" : {
"$eq" : 1.0
}
},
{
"createdTime" : {
"$lte" : ISODate("2020-04-15T08:00:00.000+08:00")
}
},
{
"createdTime" : {
"$gte" : ISODate("2020-04-01T08:00:00.000+08:00")
}
},
{
"$not" : {
"finished" : {
"$eq" : true
}
}
}
]
},
"inputStage" : {
"stage" : "IXSCAN",
"keyPattern" : {
"tryTimes" : 1.0,
"createdTime" : -1.0
},
"indexName" : "tryTimes_1_createdTime_-1",
"isMultiKey" : false,
"isUnique" : false,
"isSparse" : false,
"isPartial" : false,
"indexVersion" : 1,
"direction" : "forward",
"indexBounds" : {
"tryTimes" : [
"[MinKey, MaxKey]"
],
"createdTime" : [
"[MaxKey, MinKey]"
]
}
}
}
}
]
},
"executionStats" : {
"executionSuccess" : true,
"nReturned" : 200,
"executionTimeMillis" : 352,
"totalKeysExamined" : 48256,
"totalDocsExamined" : 48256,
"executionStages" : {
"stage" : "SORT",
"nReturned" : 200,
"executionTimeMillisEstimate" : 200,
"works" : 48459,
"advanced" : 200,
"needTime" : 48258,
"needYield" : 0,
"saveState" : 757,
"restoreState" : 757,
"isEOF" : 1,
"invalidates" : 0,
"sortPattern" : {
"tryTimes" : 1.0,
"createdTime" : -1.0
},
"memUsage" : 198706,
"memLimit" : 33554432,
"limitAmount" : 200,
"inputStage" : {
"stage" : "SORT_KEY_GENERATOR",
"nReturned" : 0,
"executionTimeMillisEstimate" : 180,
"works" : 48258,
"advanced" : 0,
"needTime" : 24539,
"needYield" : 0,
"saveState" : 757,
"restoreState" : 757,
"isEOF" : 1,
"invalidates" : 0,
"inputStage" : {
"stage" : "FETCH",
"filter" : {
"$and" : [
{
"buildNo" : {
"$eq" : 1.0
}
},
{
"$not" : {
"finished" : {
"$eq" : true
}
}
}
]
},
"nReturned" : 23718,
"executionTimeMillisEstimate" : 160,
"works" : 48257,
"advanced" : 23718,
"needTime" : 24538,
"needYield" : 0,
"saveState" : 757,
"restoreState" : 757,
"isEOF" : 1,
"invalidates" : 0,
"docsExamined" : 48256,
"alreadyHasObj" : 0,
"inputStage" : {
"stage" : "IXSCAN",
"nReturned" : 48256,
"executionTimeMillisEstimate" : 20,
"works" : 48257,
"advanced" : 48256,
"needTime" : 0,
"needYield" : 0,
"saveState" : 757,
"restoreState" : 757,
"isEOF" : 1,
"invalidates" : 0,
"keyPattern" : {
"createdTime" : 1.0
},
"indexName" : "createdTime_1",
"isMultiKey" : false,
"isUnique" : false,
"isSparse" : false,
"isPartial" : false,
"indexVersion" : 1,
"direction" : "forward",
"indexBounds" : {
"createdTime" : [
"[new Date(1585699200000), new Date(1586908800000)]"
]
},
"keysExamined" : 48256,
"dupsTested" : 0,
"dupsDropped" : 0,
"seenInvalidated" : 0
}
}
}
}
},
"serverInfo" : {
"host" : "...",
"port" : 9999,
"version" : "3.2.7",
"gitVersion" : "4249c1d2b5999ebbf1fdf3bc0e0e3b3ff5c0aaf2"
},
"ok" : 1.0}
even if I try to simplify the query to
db.getCollection('builds')
.find({ "buildNo": 1, "finished": true })
.sort({"tryTimes": 1, "createdTime": -1})
.limit(200)
, the index still doesn't work.
The wierd things is: I use the same index and query on another mongondb ver. 3.4.14.3. The index works...
Any ideas is welcomed and appreciated.
Thanks a lot!
If a query can be satisfied by multiple indexes (satisfied is used losely as Mongo actually chooses all possibly relevant indexes) defined in the collection, MongoDB will then test all the applicable indexes in parallel (meaning Mongo's performs a "race"). The first index that can returns 101 results will be selected by the query planner.
Meaning that for that certain query your using the "wrong" index wins.
What can you do?:
You can use $hint, hint basically forces Mongo to use a specific index, however Mongo this is not recommended because if changes occur Mongo will not adapt to those.
Like so:
db.getCollection('builds')
.find({ "buildNo": 1, "finished": true })
.sort({"tryTimes": 1, "createdTime": -1})
.limit(200)
.hint({tryTimes: 1, createdTime: -1})

mongodb 4.2 sort by id slow with compound index

I have docs in the fasion
{
_id: ...,
p: [
{
k: 'stringvalue',
v: 'stringvalue'
},
...
]
}
_id is provided to drivers as a sequence number of insertion, e.g. ...0001, ....0002, etc.
That works extermely well for find queries, now I have added sort condition and added _id field to the compound index (see below).
That works extermely bad around x100 slower, what could be the reason? The server has plenty of RAM.
db.getCollection('mycoll').find({ p: { '$elemMatch': { k: 'd', v: { '$gt': '2019-10-16T08:01:39.741' } } } }).sort({_id: 1}).explain()
{
"queryPlanner" : {
"plannerVersion" : 1,
"namespace" : "mydb.mycoll",
"indexFilterSet" : false,
"parsedQuery" : {
"p" : {
"$elemMatch" : {
"$and" : [
{
"k" : {
"$eq" : "d"
}
},
{
"v" : {
"$gt" : "2019-10-16T08:01:39.741"
}
}
]
}
}
},
"queryHash" : "E28632C1",
"planCacheKey" : "E28632C1",
"winningPlan" : {
"stage" : "SORT",
"sortPattern" : {
"_id" : 1
},
"inputStage" : {
"stage" : "SORT_KEY_GENERATOR",
"inputStage" : {
"stage" : "FETCH",
"filter" : {
"p" : {
"$elemMatch" : {
"$and" : [
{
"k" : {
"$eq" : "d"
}
},
{
"v" : {
"$gt" : "2019-10-16T08:01:39.741"
}
}
]
}
}
},
"inputStage" : {
"stage" : "IXSCAN",
"keyPattern" : {
"p.k" : 1,
"p.v" : 1,
"_id" : 1
},
"indexName" : "p.k_1_p.v_1__id_1",
"isMultiKey" : true,
"multiKeyPaths" : {
"p.k" : [
"p"
],
"p.v" : [
"p"
],
"_id" : [ ]
},
"isUnique" : false,
"isSparse" : false,
"isPartial" : false,
"indexVersion" : 2,
"direction" : "forward",
"indexBounds" : {
"p.k" : [
"[\"d\", \"d\"]"
],
"p.v" : [
"(\"2019-10-16T08:01:39.741\", {})"
],
"_id" : [
"[MinKey, MaxKey]"
]
}
}
}
}
},
"rejectedPlans" : [
{
"stage" : "FETCH",
"filter" : {
"p" : {
"$elemMatch" : {
"$and" : [
{
"k" : {
"$eq" : "d"
}
},
{
"v" : {
"$gt" : "2019-10-16T08:01:39.741"
}
}
]
}
}
},
"inputStage" : {
"stage" : "IXSCAN",
"keyPattern" : {
"_id" : 1
},
"indexName" : "_id_",
"isMultiKey" : false,
"multiKeyPaths" : {
"_id" : [ ]
},
"isUnique" : true,
"isSparse" : false,
"isPartial" : false,
"indexVersion" : 2,
"direction" : "forward",
"indexBounds" : {
"_id" : [
"[MinKey, MaxKey]"
]
}
}
}
]
},
"serverInfo" : {
"host" : "dev-10-178-3-247",
"port" : 27017,
"version" : "4.2.0",
"gitVersion" : "a4b751dcf51dd249c5865812b390cfd1c0129c30"
},
"ok" : 1
}
> db.getCollection('mycoll').getIndexes()
[
{
"v" : 2,
"key" : {
"_id" : 1
},
"name" : "_id_",
"ns" : "mydb.mycoll"
},
{
"v" : 2,
"key" : {
"p.k" : 1,
"p.v" : 1,
"_id" : 1
},
"name" : "p.k_1_p.v_1__id_1",
"ns" : "mydb.mycoll"
}
]
{
"executionStats" : {
"executionSuccess" : true,
"nReturned" : 1015268,
"executionTimeMillis" : 77032,
"totalKeysExamined" : 3122749,
"totalDocsExamined" : 3122749,
"executionStages" : {
"stage" : "FETCH",
"filter" : {
"p" : {
"$elemMatch" : {
"$and" : [
{
"k" : {
"$eq" : "d"
}
},
{
"v" : {
"$gt" : "2019-10-16T08:01:39.741"
}
}
]
}
}
},
"nReturned" : 1015268,
"executionTimeMillisEstimate" : 16092,
"works" : 3122750,
"advanced" : 1015268,
"needTime" : 2107481,
"needYield" : 0,
"saveState" : 24469,
"restoreState" : 24469,
"isEOF" : 1,
"docsExamined" : 3122749,
"alreadyHasObj" : 0,
"inputStage" : {
"stage" : "IXSCAN",
"nReturned" : 3122749,
"executionTimeMillisEstimate" : 492,
"works" : 3122750,
"advanced" : 3122749,
"needTime" : 0,
"needYield" : 0,
"saveState" : 24469,
"restoreState" : 24469,
"isEOF" : 1,
"keyPattern" : {
"_id" : 1
},
"indexName" : "_id_",
"isMultiKey" : false,
"multiKeyPaths" : {
"_id" : [ ]
},
"isUnique" : true,
"isSparse" : false,
"isPartial" : false,
"indexVersion" : 2,
"direction" : "forward",
"indexBounds" : {
"_id" : [
"[MinKey, MaxKey]"
]
},
"keysExamined" : 3122749,
"seeks" : 1,
"dupsTested" : 0,
"dupsDropped" : 0
}
},
"allPlansExecution" : [
{
"nReturned" : 0,
"executionTimeMillisEstimate" : 85,
"totalKeysExamined" : 9298,
"totalDocsExamined" : 9298,
"executionStages" : {
"stage" : "SORT",
"nReturned" : 0,
"executionTimeMillisEstimate" : 85,
"works" : 9300,
"advanced" : 0,
"needTime" : 9299,
"needYield" : 0,
"saveState" : 7391,
"restoreState" : 7391,
"isEOF" : 0,
"sortPattern" : {
"_id" : 1
},
"memUsage" : 33559558,
"memLimit" : 33554432,
"inputStage" : {
"stage" : "SORT_KEY_GENERATOR",
"nReturned" : 9298,
"executionTimeMillisEstimate" : 71,
"works" : 9299,
"advanced" : 9298,
"needTime" : 1,
"needYield" : 0,
"saveState" : 7391,
"restoreState" : 7391,
"isEOF" : 0,
"inputStage" : {
"stage" : "FETCH",
"filter" : {
"p" : {
"$elemMatch" : {
"$and" : [
{
"k" : {
"$eq" : "d"
}
},
{
"v" : {
"$gt" : "2019-10-16T08:01:39.741"
}
}
]
}
}
},
"nReturned" : 9298,
"executionTimeMillisEstimate" : 58,
"works" : 9298,
"advanced" : 9298,
"needTime" : 0,
"needYield" : 0,
"saveState" : 7391,
"restoreState" : 7391,
"isEOF" : 0,
"docsExamined" : 9298,
"alreadyHasObj" : 0,
"inputStage" : {
"stage" : "IXSCAN",
"nReturned" : 9298,
"executionTimeMillisEstimate" : 0,
"works" : 9298,
"advanced" : 9298,
"needTime" : 0,
"needYield" : 0,
"saveState" : 7391,
"restoreState" : 7391,
"isEOF" : 0,
"keyPattern" : {
"p.k" : 1,
"p.v" : 1,
"_id" : 1
},
"indexName" : "p.k_1_p.v_1__id_1",
"isMultiKey" : true,
"multiKeyPaths" : {
"p.k" : [
"p"
],
"p.v" : [
"p"
],
"_id" : [ ]
},
"isUnique" : false,
"isSparse" : false,
"isPartial" : false,
"indexVersion" : 2,
"direction" : "forward",
"indexBounds" : {
"p.k" : [
"[\"d\", \"d\"]"
],
"p.v" : [
"(\"2019-10-16T08:01:39.741\", {})"
],
"_id" : [
"[MinKey, MaxKey]"
]
},
"keysExamined" : 9298,
"seeks" : 1,
"dupsTested" : 9298,
"dupsDropped" : 0
}
}
}
}
},
{
"nReturned" : 0,
"executionTimeMillisEstimate" : 85,
"totalKeysExamined" : 9298,
"totalDocsExamined" : 9298,
"executionStages" : {
"stage" : "SORT",
"nReturned" : 0,
"executionTimeMillisEstimate" : 85,
"works" : 9301,
"advanced" : 0,
"needTime" : 9299,
"needYield" : 0,
"saveState" : 24469,
"restoreState" : 24469,
"isEOF" : 0,
"sortPattern" : {
"_id" : 1
},
"memUsage" : 33559558,
"memLimit" : 33554432,
"inputStage" : {
"stage" : "SORT_KEY_GENERATOR",
"nReturned" : 9298,
"executionTimeMillisEstimate" : 71,
"works" : 9299,
"advanced" : 9298,
"needTime" : 1,
"needYield" : 0,
"saveState" : 24469,
"restoreState" : 24469,
"isEOF" : 0,
"inputStage" : {
"stage" : "FETCH",
"filter" : {
"p" : {
"$elemMatch" : {
"$and" : [
{
"k" : {
"$eq" : "d"
}
},
{
"v" : {
"$gt" : "2019-10-16T08:01:39.741"
}
}
]
}
}
},
"nReturned" : 9298,
"executionTimeMillisEstimate" : 58,
"works" : 9298,
"advanced" : 9298,
"needTime" : 0,
"needYield" : 0,
"saveState" : 24469,
"restoreState" : 24469,
"isEOF" : 0,
"docsExamined" : 9298,
"alreadyHasObj" : 0,
"inputStage" : {
"stage" : "IXSCAN",
"nReturned" : 9298,
"executionTimeMillisEstimate" : 0,
"works" : 9298,
"advanced" : 9298,
"needTime" : 0,
"needYield" : 0,
"saveState" : 24469,
"restoreState" : 24469,
"isEOF" : 0,
"keyPattern" : {
"p.k" : 1,
"p.v" : 1,
"_id" : 1
},
"indexName" : "p.k_1_p.v_1__id_1",
"isMultiKey" : true,
"multiKeyPaths" : {
"p.k" : [
"p"
],
"p.v" : [
"p"
],
"_id" : [ ]
},
"isUnique" : false,
"isSparse" : false,
"isPartial" : false,
"indexVersion" : 2,
"direction" : "forward",
"indexBounds" : {
"p.k" : [
"[\"d\", \"d\"]"
],
"p.v" : [
"(\"2019-10-16T08:01:39.741\", {})"
],
"_id" : [
"[MinKey, MaxKey]"
]
},
"keysExamined" : 9298,
"seeks" : 1,
"dupsTested" : 9298,
"dupsDropped" : 0
}
}
}
}
}
]
},
"ok" : 1
}

Index intersection queries performing the same as COLLSCAN

I'm going through the existing indexes on a fairly old MongoDB database which has recently been upgraded from 2.something to 3.4.
The code accessing it is convoluted, automagic, and spaghetti-heavy, plus it allows web-facing frontend code to do arbitrary queries, so it's pretty difficult to get an overview of exactly what queries are made. Doing a bit of profiling, I quickly discovered that a lot of queries were missing indexes, either because logical indexes were missing or misspelled (yeah!), or because someone had assumed that a compound index would support queries on non-prefix parts of them.
Such an example was with a users collection where a compound index, { boxes._id: 1, _deleted: 1 } was missed by a ton of queries filtering by { _deleted: { $exists: false } }.
I wiped it, and created single-field indexes instead, having read up on the index intersection feature which is now part of the version of the MongoDB server backing this app:
db.users.dropIndex({ 'boxes._id': 1, _deleted: 1 });
db.users.ensureIndex({ 'boxes._id': 1 });
db.users.ensureIndex({ '_deleted': 1 });
So far, so good. The dataset here is not very large, so I saw no immediate issue, performance-wise, by dropping the compound index and support index intersection instead. AFAIU from the docs and the interwebs, the performance gains from using compound indexes are mostly felt with really large collections, and for this one, we're looking at about 11k documents.
Simple count queries on either of the two indexed fields yield satisfying responses while hitting the keys:
db.runCommand({ explain: { count: 'users', query: { 'boxes._id': ObjectId('597745846ca2582d8b364c38') }, verbosity: 'executionStats' }})
// "executionTimeMillis" : 8
db.runCommand({ explain: { count: 'users', query: { _deleted: { $exists: false } }, verbosity: 'executionStats' }})
// "executionTimeMillis" : 35
(Note that this is on my old MacBook Air, and compared to query times I'm seeing in the performance log when not using explain, then "normal" response times seem to be less than 25% of those reported with explain in the mongo shell)
However, if I filter on both those fields thus triggering the use of an intersection index, I see a massive performance penalty:
{
"queryPlanner" : {
"plannerVersion" : 1,
"namespace" : "bl.users",
"indexFilterSet" : false,
"parsedQuery" : {
"$and" : [
{
"boxes._id" : {
"$eq" : ObjectId("597745846ca2582d8b364c38")
}
},
{
"$nor" : [ { "_deleted" : { "$exists" : true } } ]
}
]
},
"winningPlan" : {
"stage" : "FETCH",
"filter" : {
"$and" : [
{
"$nor" : [ { "_deleted" : { "$exists" : true } } ]
},
{
"boxes._id" : {
"$eq" : ObjectId("597745846ca2582d8b364c38")
}
}
]
},
"inputStage" : {
"stage" : "IXSCAN",
"keyPattern" : { "_deleted" : 1 },
"indexName" : "_deleted_1",
"isMultiKey" : false,
"multiKeyPaths" : { "_deleted" : [ ] },
"isUnique" : false,
"isSparse" : false,
"isPartial" : false,
"indexVersion" : 2,
"direction" : "forward",
"indexBounds" : { "_deleted" : [ "[null, null]" ] }
}
},
"rejectedPlans" : [
{
"stage" : "FETCH",
"filter" : {
"$nor" : [ { "_deleted" : { "$exists" : true } } ]
},
"inputStage" : {
"stage" : "IXSCAN",
"keyPattern" : {
"boxes._id" : 1
},
"indexName" : "boxes._id_1",
"isMultiKey" : true,
"multiKeyPaths" : {
"boxes._id" : [
"boxes"
]
},
"isUnique" : false,
"isSparse" : false,
"isPartial" : false,
"indexVersion" : 2,
"direction" : "forward",
"indexBounds" : {
"boxes._id" : [
"[ObjectId('597745846ca2582d8b364c38'), ObjectId('597745846ca2582d8b364c38')]"
]
}
}
},
{
"stage" : "FETCH",
"filter" : {
"$and" : [
{
"boxes._id" : {
"$eq" : ObjectId("597745846ca2582d8b364c38")
}
},
{
"$nor" : [ { "_deleted" : { "$exists" : true } } ]
}
]
},
"inputStage" : {
"stage" : "AND_SORTED",
"inputStages" : [
{
"stage" : "IXSCAN",
"keyPattern" : {
"boxes._id" : 1
},
"indexName" : "boxes._id_1",
"isMultiKey" : true,
"multiKeyPaths" : {
"boxes._id" : [
"boxes"
]
},
"isUnique" : false,
"isSparse" : false,
"isPartial" : false,
"indexVersion" : 2,
"direction" : "forward",
"indexBounds" : {
"boxes._id" : [
"[ObjectId('597745846ca2582d8b364c38'), ObjectId('597745846ca2582d8b364c38')]"
]
}
},
{
"stage" : "IXSCAN",
"keyPattern" : { "_deleted" : 1 },
"indexName" : "_deleted_1",
"isMultiKey" : false,
"multiKeyPaths" : { "_deleted" : [ ] },
"isUnique" : false,
"isSparse" : false,
"isPartial" : false,
"indexVersion" : 2,
"direction" : "forward",
"indexBounds" : {
"_deleted" : [ "[null, null]" ]
}
}
]
}
}
]
},
"executionStats" : {
"executionSuccess" : true,
"nReturned" : 11098,
"executionTimeMillis" : 731,
"totalKeysExamined" : 11098,
"totalDocsExamined" : 11098,
"executionStages" : {
"stage" : "FETCH",
"filter" : {
"$and" : [
{
"$nor" : [ { "_deleted" : { "$exists" : true } } ]
},
{
"boxes._id" : {
"$eq" : ObjectId("597745846ca2582d8b364c38")
}
}
]
},
"nReturned" : 11098,
"executionTimeMillisEstimate" : 702,
"works" : 11099,
"advanced" : 11098,
"needTime" : 0,
"needYield" : 0,
"saveState" : 127,
"restoreState" : 127,
"isEOF" : 1,
"invalidates" : 0,
"docsExamined" : 11098,
"alreadyHasObj" : 0,
"inputStage" : {
"stage" : "IXSCAN",
"nReturned" : 11098,
"executionTimeMillisEstimate" : 49,
"works" : 11099,
"advanced" : 11098,
"needTime" : 0,
"needYield" : 0,
"saveState" : 127,
"restoreState" : 127,
"isEOF" : 1,
"invalidates" : 0,
"keyPattern" : { "_deleted" : 1 },
"indexName" : "_deleted_1",
"isMultiKey" : false,
"multiKeyPaths" : { "_deleted" : [ ] },
"isUnique" : false,
"isSparse" : false,
"isPartial" : false,
"indexVersion" : 2,
"direction" : "forward",
"indexBounds" : {
"_deleted" : [ "[null, null]" ]
},
"keysExamined" : 11098,
"seeks" : 1,
"dupsTested" : 0,
"dupsDropped" : 0,
"seenInvalidated" : 0
}
},
"allPlansExecution" : [
{
"nReturned" : 101,
"executionTimeMillisEstimate" : 0,
"totalKeysExamined" : 101,
"totalDocsExamined" : 101,
"executionStages" : {
"stage" : "FETCH",
"filter" : {
"$nor" : [ { "_deleted" : { "$exists" : true } } ]
},
"nReturned" : 101,
"executionTimeMillisEstimate" : 0,
"works" : 101,
"advanced" : 101,
"needTime" : 0,
"needYield" : 0,
"saveState" : 3,
"restoreState" : 3,
"isEOF" : 0,
"invalidates" : 0,
"docsExamined" : 101,
"alreadyHasObj" : 0,
"inputStage" : {
"stage" : "IXSCAN",
"nReturned" : 101,
"executionTimeMillisEstimate" : 0,
"works" : 101,
"advanced" : 101,
"needTime" : 0,
"needYield" : 0,
"saveState" : 3,
"restoreState" : 3,
"isEOF" : 0,
"invalidates" : 0,
"keyPattern" : {
"boxes._id" : 1
},
"indexName" : "boxes._id_1",
"isMultiKey" : true,
"multiKeyPaths" : {
"boxes._id" : [
"boxes"
]
},
"isUnique" : false,
"isSparse" : false,
"isPartial" : false,
"indexVersion" : 2,
"direction" : "forward",
"indexBounds" : {
"boxes._id" : [
"[ObjectId('597745846ca2582d8b364c38'), ObjectId('597745846ca2582d8b364c38')]"
]
},
"keysExamined" : 101,
"seeks" : 1,
"dupsTested" : 101,
"dupsDropped" : 0,
"seenInvalidated" : 0
}
}
},
{
"nReturned" : 50,
"executionTimeMillisEstimate" : 12,
"totalKeysExamined" : 101,
"totalDocsExamined" : 50,
"executionStages" : {
"stage" : "FETCH",
"filter" : {
"$and" : [
{
"boxes._id" : {
"$eq" : ObjectId("597745846ca2582d8b364c38")
}
},
{
"$nor" : [ { "_deleted" : { "$exists" : true } } ]
}
]
},
"nReturned" : 50,
"executionTimeMillisEstimate" : 12,
"works" : 101,
"advanced" : 50,
"needTime" : 51,
"needYield" : 0,
"saveState" : 3,
"restoreState" : 3,
"isEOF" : 0,
"invalidates" : 0,
"docsExamined" : 50,
"alreadyHasObj" : 0,
"inputStage" : {
"stage" : "AND_SORTED",
"nReturned" : 50,
"executionTimeMillisEstimate" : 12,
"works" : 101,
"advanced" : 50,
"needTime" : 51,
"needYield" : 0,
"saveState" : 3,
"restoreState" : 3,
"isEOF" : 0,
"invalidates" : 0,
"flagged" : 0,
"failedAnd_0" : 0,
"failedAnd_1" : 0,
"inputStages" : [
{
"stage" : "IXSCAN",
"nReturned" : 51,
"executionTimeMillisEstimate" : 0,
"works" : 51,
"advanced" : 51,
"needTime" : 0,
"needYield" : 0,
"saveState" : 3,
"restoreState" : 3,
"isEOF" : 0,
"invalidates" : 0,
"keyPattern" : {
"boxes._id" : 1
},
"indexName" : "boxes._id_1",
"isMultiKey" : true,
"multiKeyPaths" : {
"boxes._id" : [
"boxes"
]
},
"isUnique" : false,
"isSparse" : false,
"isPartial" : false,
"indexVersion" : 2,
"direction" : "forward",
"indexBounds" : {
"boxes._id" : [
"[ObjectId('597745846ca2582d8b364c38'), ObjectId('597745846ca2582d8b364c38')]"
]
},
"keysExamined" : 51,
"seeks" : 1,
"dupsTested" : 51,
"dupsDropped" : 0,
"seenInvalidated" : 0
},
{
"stage" : "IXSCAN",
"nReturned" : 50,
"executionTimeMillisEstimate" : 12,
"works" : 50,
"advanced" : 50,
"needTime" : 0,
"needYield" : 0,
"saveState" : 3,
"restoreState" : 3,
"isEOF" : 0,
"invalidates" : 0,
"keyPattern" : { "_deleted" : 1 },
"indexName" : "_deleted_1",
"isMultiKey" : false,
"multiKeyPaths" : { "_deleted" : [ ] },
"isUnique" : false,
"isSparse" : false,
"isPartial" : false,
"indexVersion" : 2,
"direction" : "forward",
"indexBounds" : {
"_deleted" : [ "[null, null]" ]
},
"keysExamined" : 50,
"seeks" : 1,
"dupsTested" : 0,
"dupsDropped" : 0,
"seenInvalidated" : 0
}
]
}
}
},
{
"nReturned" : 101,
"executionTimeMillisEstimate" : 11,
"totalKeysExamined" : 101,
"totalDocsExamined" : 101,
"executionStages" : {
"stage" : "FETCH",
"filter" : {
"$and" : [
{
"$nor" : [ { "_deleted" : { "$exists" : true } } ]
},
{
"boxes._id" : {
"$eq" : ObjectId("597745846ca2582d8b364c38")
}
}
]
},
"nReturned" : 101,
"executionTimeMillisEstimate" : 11,
"works" : 101,
"advanced" : 101,
"needTime" : 0,
"needYield" : 0,
"saveState" : 3,
"restoreState" : 3,
"isEOF" : 0,
"invalidates" : 0,
"docsExamined" : 101,
"alreadyHasObj" : 0,
"inputStage" : {
"stage" : "IXSCAN",
"nReturned" : 101,
"executionTimeMillisEstimate" : 0,
"works" : 101,
"advanced" : 101,
"needTime" : 0,
"needYield" : 0,
"saveState" : 3,
"restoreState" : 3,
"isEOF" : 0,
"invalidates" : 0,
"keyPattern" : { "_deleted" : 1 },
"indexName" : "_deleted_1",
"isMultiKey" : false,
"multiKeyPaths" : { "_deleted" : [ ] },
"isUnique" : false,
"isSparse" : false,
"isPartial" : false,
"indexVersion" : 2,
"direction" : "forward",
"indexBounds" : {
"_deleted" : [ "[null, null]" ]
},
"keysExamined" : 101,
"seeks" : 1,
"dupsTested" : 0,
"dupsDropped" : 0,
"seenInvalidated" : 0
}
}
}
]
}
}
The same query hitting the compound index:
{
"queryPlanner" : {
"plannerVersion" : 1,
"namespace" : "bl.users",
"indexFilterSet" : false,
"parsedQuery" : {
"$and" : [
{
"boxes._id" : {
"$eq" : ObjectId("597745846ca2582d8b364c38")
}
},
{
"$nor" : [ { "_deleted" : { "$exists" : true } } ]
}
]
},
"winningPlan" : {
"stage" : "COUNT",
"inputStage" : {
"stage" : "FETCH",
"filter" : {
"$nor" : [ { "_deleted" : { "$exists" : true } } ]
},
"inputStage" : {
"stage" : "IXSCAN",
"keyPattern" : {
"boxes._id" : 1,
"_deleted" : 1
},
"indexName" : "boxes._id_1__deleted_1",
"isMultiKey" : true,
"multiKeyPaths" : {
"boxes._id" : [
"boxes"
],
"_deleted" : [ ]
},
"isUnique" : false,
"isSparse" : false,
"isPartial" : false,
"indexVersion" : 2,
"direction" : "forward",
"indexBounds" : {
"boxes._id" : [
"[ObjectId('597745846ca2582d8b364c38'), ObjectId('597745846ca2582d8b364c38')]"
],
"_deleted" : [ "[null, null]" ]
}
}
}
},
"rejectedPlans" : [ ]
},
"executionStats" : {
"executionSuccess" : true,
"nReturned" : 0,
"executionTimeMillis" : 37,
"totalKeysExamined" : 11098,
"totalDocsExamined" : 11098,
"executionStages" : {
"stage" : "COUNT",
"nReturned" : 0,
"executionTimeMillisEstimate" : 35,
"works" : 11099,
"advanced" : 0,
"needTime" : 11098,
"needYield" : 0,
"saveState" : 87,
"restoreState" : 87,
"isEOF" : 1,
"invalidates" : 0,
"nCounted" : 11098,
"nSkipped" : 0,
"inputStage" : {
"stage" : "FETCH",
"filter" : {
"$nor" : [ { "_deleted" : { "$exists" : true } } ]
},
"nReturned" : 11098,
"executionTimeMillisEstimate" : 35,
"works" : 11099,
"advanced" : 11098,
"needTime" : 0,
"needYield" : 0,
"saveState" : 87,
"restoreState" : 87,
"isEOF" : 1,
"invalidates" : 0,
"docsExamined" : 11098,
"alreadyHasObj" : 0,
"inputStage" : {
"stage" : "IXSCAN",
"nReturned" : 11098,
"executionTimeMillisEstimate" : 23,
"works" : 11099,
"advanced" : 11098,
"needTime" : 0,
"needYield" : 0,
"saveState" : 87,
"restoreState" : 87,
"isEOF" : 1,
"invalidates" : 0,
"keyPattern" : {
"boxes._id" : 1,
"_deleted" : 1
},
"indexName" : "boxes._id_1__deleted_1",
"isMultiKey" : true,
"multiKeyPaths" : {
"boxes._id" : [
"boxes"
],
"_deleted" : [ ]
},
"isUnique" : false,
"isSparse" : false,
"isPartial" : false,
"indexVersion" : 2,
"direction" : "forward",
"indexBounds" : {
"boxes._id" : [
"[ObjectId('597745846ca2582d8b364c38'), ObjectId('597745846ca2582d8b364c38')]"
],
"_deleted" : [ "[null, null]" ]
},
"keysExamined" : 11098,
"seeks" : 1,
"dupsTested" : 11098,
"dupsDropped" : 0,
"seenInvalidated" : 0
}
}
},
"allPlansExecution" : [ ]
}
}
Replacing the compound index with just a single index on boxes._id yields pretty much identical performance to having the compound key on both filtered fields:
{
"queryPlanner" : {
"plannerVersion" : 1,
"namespace" : "bl.users",
"indexFilterSet" : false,
"parsedQuery" : {
"$and" : [
{
"boxes._id" : {
"$eq" : ObjectId("597745846ca2582d8b364c38")
}
},
{
"$nor" : [ { "_deleted" : { "$exists" : true } } ]
}
]
},
"winningPlan" : {
"stage" : "COUNT",
"inputStage" : {
"stage" : "FETCH",
"filter" : {
"$nor" : [ { "_deleted" : { "$exists" : true } } ]
},
"inputStage" : {
"stage" : "IXSCAN",
"keyPattern" : {
"boxes._id" : 1
},
"indexName" : "boxes._id_1",
"isMultiKey" : true,
"multiKeyPaths" : {
"boxes._id" : [
"boxes"
]
},
"isUnique" : false,
"isSparse" : false,
"isPartial" : false,
"indexVersion" : 2,
"direction" : "forward",
"indexBounds" : {
"boxes._id" : [
"[ObjectId('597745846ca2582d8b364c38'), ObjectId('597745846ca2582d8b364c38')]"
]
}
}
}
},
"rejectedPlans" : [ ]
},
"executionStats" : {
"executionSuccess" : true,
"nReturned" : 0,
"executionTimeMillis" : 31,
"totalKeysExamined" : 11098,
"totalDocsExamined" : 11098,
"executionStages" : {
"stage" : "COUNT",
"nReturned" : 0,
"executionTimeMillisEstimate" : 34,
"works" : 11099,
"advanced" : 0,
"needTime" : 11098,
"needYield" : 0,
"saveState" : 88,
"restoreState" : 88,
"isEOF" : 1,
"invalidates" : 0,
"nCounted" : 11098,
"nSkipped" : 0,
"inputStage" : {
"stage" : "FETCH",
"filter" : {
"$nor" : [ { "_deleted" : { "$exists" : true } } ]
},
"nReturned" : 11098,
"executionTimeMillisEstimate" : 34,
"works" : 11099,
"advanced" : 11098,
"needTime" : 0,
"needYield" : 0,
"saveState" : 88,
"restoreState" : 88,
"isEOF" : 1,
"invalidates" : 0,
"docsExamined" : 11098,
"alreadyHasObj" : 0,
"inputStage" : {
"stage" : "IXSCAN",
"nReturned" : 11098,
"executionTimeMillisEstimate" : 11,
"works" : 11099,
"advanced" : 11098,
"needTime" : 0,
"needYield" : 0,
"saveState" : 88,
"restoreState" : 88,
"isEOF" : 1,
"invalidates" : 0,
"keyPattern" : {
"boxes._id" : 1
},
"indexName" : "boxes._id_1",
"isMultiKey" : true,
"multiKeyPaths" : {
"boxes._id" : [
"boxes"
]
},
"isUnique" : false,
"isSparse" : false,
"isPartial" : false,
"indexVersion" : 2,
"direction" : "forward",
"indexBounds" : {
"boxes._id" : [
"[ObjectId('597745846ca2582d8b364c38'), ObjectId('597745846ca2582d8b364c38')]"
]
},
"keysExamined" : 11098,
"seeks" : 1,
"dupsTested" : 11098,
"dupsDropped" : 0,
"seenInvalidated" : 0
}
}
},
"allPlansExecution" : [ ]
}
}
Finally, dropping all indexes on these fields, triggering a COLLSCAN yields performance pretty much identical to the index intersection one:
{
"queryPlanner" : {
"plannerVersion" : 1,
"namespace" : "bl.users",
"indexFilterSet" : false,
"parsedQuery" : {
"$and" : [
{
"ideaboxes._id" : {
"$eq" : ObjectId("597745846ca2582d8b364c38")
}
},
{
"$nor" : [ { "_deleted" : { "$exists" : true } } ]
}
]
},
"winningPlan" : {
"stage" : "COUNT",
"inputStage" : {
"stage" : "COLLSCAN",
"filter" : {
"$and" : [
{
"ideaboxes._id" : {
"$eq" : ObjectId("597745846ca2582d8b364c38")
}
},
{
"$nor" : [ { "_deleted" : { "$exists" : true } } ]
}
]
},
"direction" : "forward"
}
},
"rejectedPlans" : [ ]
},
"executionStats" : {
"executionSuccess" : true,
"nReturned" : 0,
"executionTimeMillis" : 848,
"totalKeysExamined" : 0,
"totalDocsExamined" : 11109,
"executionStages" : {
"stage" : "COUNT",
"nReturned" : 0,
"executionTimeMillisEstimate" : 847,
"works" : 11111,
"advanced" : 0,
"needTime" : 11110,
"needYield" : 0,
"saveState" : 123,
"restoreState" : 123,
"isEOF" : 1,
"invalidates" : 0,
"nCounted" : 11098,
"nSkipped" : 0,
"inputStage" : {
"stage" : "COLLSCAN",
"filter" : {
"$and" : [
{
"ideaboxes._id" : {
"$eq" : ObjectId("597745846ca2582d8b364c38")
}
},
{
"$nor" : [ { "_deleted" : { "$exists" : true } } ]
}
]
},
"nReturned" : 11098,
"executionTimeMillisEstimate" : 847,
"works" : 11111,
"advanced" : 11098,
"needTime" : 12,
"needYield" : 0,
"saveState" : 123,
"restoreState" : 123,
"isEOF" : 1,
"invalidates" : 0,
"direction" : "forward",
"docsExamined" : 11109
}
},
"allPlansExecution" : [ ]
}
}
Surely getting COLLSCAN performance with index intersection queries can't be right? I admit I'm very new with Mongo, so I'm also quite ignorant when trying to decipher this report — the answer may be staring me in the face.
I've tested the same queries on Mongo 3.2 on an ObjectRocket instance, and while their servers are much faster than my ageing laptop, they exhibit the same numbers relatively speaking.
Any ideas why this is happening?
Thank you :)

MongoDB $geoWithin query very slow

I have a huge collection of documents (~1 milion), each doc is quite big (avgObjSize: 13268). Each document has a geo point:
Accomodation:
{
"location" : {
[...]
"geoLocation" : {
"type" : "Point",
"coordinates" : [
-42.61343486,
71.70936503
]
}
}
}
I have the following index:
{
"location.geoLocation" : "2dsphere"
}
I do this simple query (it should keep a 85km radius):
db.getCollection('Accomodation').find({
"location.geoLocation" : {
"$geoWithin" : {
"$centerSphere" : [
[
2.34682537615297,
48.8536252472747
],
0.0131543876703093
]
}
}})).limit(100)
the query execution takes from 1 to 6 seconds, and I think it's slow.
Even if the server is not powerfull it should take so much less time to get 100 docs, it seems it uses the index, so the docs in the area should not even be fetched for the scan.
What am I missing?
This is the query stats
{
"queryPlanner" : {
"plannerVersion" : 1,
"namespace" : "Stage-BluePillow.Accomodation",
"indexFilterSet" : false,
"parsedQuery" : {
"location.geoLocation" : {
"$geoWithin" : {
"$centerSphere" : [
[
2.34682537615297,
48.8536252472747
],
0.0131543876703093
]
}
}
},
"winningPlan" : {
"stage" : "LIMIT",
"limitAmount" : 100,
"inputStage" : {
"stage" : "FETCH",
"filter" : {
"location.geoLocation" : {
"$geoWithin" : {
"$centerSphere" : [
[
2.34682537615297,
48.8536252472747
],
0.0131543876703093
]
}
}
},
"inputStage" : {
"stage" : "IXSCAN",
"keyPattern" : {
"location.geoLocation" : "2dsphere"
},
"indexName" : "location.geoLocation_2dsphere",
"isMultiKey" : false,
"isUnique" : false,
"isSparse" : false,
"isPartial" : false,
"indexVersion" : 1,
"direction" : "forward",
"indexBounds" : {
"location.geoLocation" : [
"[5116089176692883456, 5116089176692883456]",
"[5170132372221329408, 5170132372221329408]",
[...]
"[5183361696126730241, 5183502433615085567]",
"[5183643171103440896, 5183643171103440896]"
]
}
}
}
},
"executionStats" : {
"executionSuccess" : true,
"nReturned" : 100,
"executionTimeMillis" : 1399,
"totalKeysExamined" : 151,
"totalDocsExamined" : 142,
"executionStages" : {
"stage" : "LIMIT",
"nReturned" : 100,
"executionTimeMillisEstimate" : 1180,
"works" : 152,
"advanced" : 100,
"needTime" : 51,
"needYield" : 0,
"saveState" : 35,
"restoreState" : 35,
"isEOF" : 1,
"invalidates" : 0,
"limitAmount" : 100,
"inputStage" : {
"stage" : "FETCH",
"filter" : {
"location.geoLocation" : {
"$geoWithin" : {
"$centerSphere" : [
[
2.34682537615297,
48.8536252472747
],
0.0131543876703093
]
}
}
},
"nReturned" : 100,
"executionTimeMillisEstimate" : 1180,
"works" : 151,
"advanced" : 100,
"needTime" : 51,
"needYield" : 0,
"saveState" : 35,
"restoreState" : 35,
"isEOF" : 0,
"invalidates" : 0,
"docsExamined" : 142,
"alreadyHasObj" : 0,
"inputStage" : {
"stage" : "IXSCAN",
"nReturned" : 142,
"executionTimeMillisEstimate" : 40,
"works" : 151,
"advanced" : 142,
"needTime" : 9,
"needYield" : 0,
"saveState" : 35,
"restoreState" : 35,
"isEOF" : 0,
"invalidates" : 0,
"keyPattern" : {
"location.geoLocation" : "2dsphere"
},
"indexName" : "location.geoLocation_2dsphere",
"isMultiKey" : false,
"isUnique" : false,
"isSparse" : false,
"isPartial" : false,
"indexVersion" : 1,
"direction" : "forward",
"indexBounds" : {
"location.geoLocation" : [
"[5116089176692883456, 5116089176692883456]",
"[5170132372221329408, 5170132372221329408]",
[...]
"[5183361696126730241, 5183502433615085567]",
"[5183643171103440896, 5183643171103440896]"
]
},
"keysExamined" : 151,
"dupsTested" : 0,
"dupsDropped" : 0,
"seenInvalidated" : 0
}
}
}
},
"serverInfo" : {
"host" : "metasearch",
"port" : 27017,
"version" : "3.2.10",
"gitVersion" : "79d9b3ab5ce20f51c272b4411202710a082d0317"
},
"ok" : 1.0
}