bottom line / tl; dr: Index b can be omitted if a and c requested for equality or inequality, but not for sorting by c .
This is a very good question. Unfortunately, I could not find anything that would authoritatively answer this in more detail. I believe that the implementation of such requests has improved in recent years, so I would not trust the old materials on this topic.
This is all quite complicated because it depends on the selectivity of your indices and whether you are asking for equality, inequality and / or sorting, so explain() is your only friend, but here are some things I found:
Caution What is now a mixture of experimental results, reasoning and guessing. Perhaps I am distorting Kyle's analogy too much, and I can even be completely wrong (and no luck, because my test results are not consistent with my reasoning).
It is clear that you can use the index A, which, depending on the selectivity of A, is certainly very useful. Skipping B can be difficult or not. Let it be like the Kyle Cookbook Example :
French Beef ... Chicken Coq au Vin Roasted Chicken Lamb ... ...
If you now ask me to find a French dish called "Chateaubriand", I can use the index a , and since I donβt know the ingredient, you have to scan all the dishes in a . On the other hand, I know that the list of dishes in each category is sorted by index c , so I will need to look for lines starting with, say, βChaβ in each list of ingredients. If there are 50 ingredients, I will need 50 search queries instead of one but it is much better than scanning every French dish!
In my experiments, the number was much less than the number of different values ββin b : it never exceeded 2. However, I tested it with only one collection, and this is probably due to the selectivity of the b index.
If you asked me to give you an alphabetically sorted list of all French dishes , I would be in trouble . Now the c index is useless, I have to combine the sorting of all these index lists. I will have to scan every item to do this.
This reflects my tests. Here are some simplified results. The original collection has datetimes, ints and strings, but I wanted everything to be simple, so now all ints.
Essentially, there are only two classes of queries: those where nscanned <= 2 * limit , and those that should scan the entire collection (120 thousand documents). The index is {a, b, c} :
// fast (range query on c while skipping b) > db.Test.find({"a" : 43, "c" : { $lte : 45454 }}); // slow (sorting) > db.Test.find({"a" : 43, "c" : { $lte : 45454 }}).sort({ "c" : -1}); > db.Test.find({"a" : 43, "c" : { $lte : 45454 }}).sort({ "b" : -1}); // fast (can sort on c if b included in the query) > db.Test.find({"a" : 43, "b" : 7887, "c" : { $lte : 45454 }}).sort({ "c" : -1}); // fast (older tutorials claim this is slow) > db.Test.find({"a" : {$gte : 43}, "c" : { $lte : 45454 }});
Your mileage will be different.