I recently had to optimize certain sets of queries on our MongoDB, and run into this particular problem:
say I have a query that match on A
and B
, then do a range select on C
, and output by sorting on D
, so in shell they look like:
db.collection.find({ A: 'something', B: 'something-else', C: { $gt: 100 } })
.sort({ D: -1 }).limit(10)
I read a post last year that talked about creating index for such scenario, their basic rules:
- Exact value match field go first
- Sorting field comes second
- Range search ($in, $gt etc.) field comes last
Their tree explanation looks reasonable so I went ahead and created an index as such:
db.collection.ensureIndex({ A:1, B:1, D:-1, C:-1 })
Now the problem comes: mongodb decides BasicCursor is better than this index. If I hint
the full index it works (and much faster), but doing that would require quite a few changes on our codebase, so we are trying to avoid that if at all possible.
My questions are:
Why does mongodb query optimizer decides
{ A:1, E:-1 }
,{ D:-1 }
or even BasicCursor are better than{ A:1, B:1, D:-1, C:-1 }
, when my query includes all 4 fields.Is
{ A:1, D:-1 }
redundant, mongo docs does say using partial index is less efficient?
Furthermore, we also have queries like following:
db.collection.find({ A: { $in : ['str1','str2'] }, B: 'something', C: { $gt: 100 } })
.sort({ D: -1 }).limit(10)
To efficiently query it, do we need an extra index like following? Frankly I am not sure how will MongoDB query optimizer treat them.
db.collection.ensureIndex({ B:1, D:-1, C:-1, A:1 })
These are the explain for my query with and without hint.
- with hint (full index): http://pastebin.com/xtpJ3dsf
- with hint (A,D index): http://pastebin.com/v66QmtsP
- without hint: http://pastebin.com/QAtM0WN0
- without hint (dropped other index): http://pastebin.com/6ZDweiNX
Turns out it was defaulting to { A:1, E:-1 }
not { A:1, D:-1 }
, which seem even stranger as we did't query on field E.
I dropped the index on { A:1, E:-1 }
, now explain tells me it defaults to { D:-1 }
, so I dropped it as well, now MongoDB begin using BasicCursor
... It doesn't seem to like neither my full index nor the A:1, D:-1
index (despite hint result in much better performance).
This feels weird.