[SERVER-20913] DateTime index ignored / horrible performance Created: 14/Oct/15 Updated: 26/Nov/15 Resolved: 14/Oct/15 |
|
| Status: | Closed |
| Project: | Core Server |
| Component/s: | Querying |
| Affects Version/s: | 2.2.0, 3.0.6 |
| Fix Version/s: | None |
| Type: | Bug | Priority: | Minor - P4 |
| Reporter: | Rob Janssen | Assignee: | David Storch |
| Resolution: | Duplicate | Votes: | 0 |
| Labels: | None | ||
| Remaining Estimate: | Not Specified | ||
| Time Spent: | Not Specified | ||
| Original Estimate: | Not Specified | ||
| Issue Links: |
|
||||||||||||||||
| Operating System: | ALL | ||||||||||||||||
| Participants: | |||||||||||||||||
| Description |
|
We have recently moved from a (single instance) MongoDB server 2.2.0 on Linux to a (single instance) MongoDB server 3.0.6 on Windows for a specific project. We have a collection that contains ~1.3 million documents. The following query to find messages for a specific 24h period performs perfectly fine on 2.2.0:
Explain:
(Though I don't know what's going on with the weird
We copied the collection to the new 3.0 (windows) server. And ran the same query; this took over 9 minutes to complete. I have re-created the index but that didn't help. The explain on this (win, 3.0.6) host looks like this:
If I change the query to 'greaterorequal than date X' instead of 'greaterorequal than date X and less than date Y' the query performs fine:
Explain:
It seems that a range query "X => date1 X $and X < date2" somehow trips the queryplanner into not using the index whereas "X >= date1" is fine. If there's anything I can to to help or provide more information then please let me know. |
| Comments |
| Comment by Asya Kamsky [ 26/Nov/15 ] | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
robiii please note that if your original query was intended to use the same timestamp to match both conditions, i.e.
expresses that you are looking for timestamp values between the two dates (as opposed to documents which have one timestamp satisfy one condition and the other satisfy the other condition) then the correct way to query for those is with $elemMatch. That expresses that the same array element must satisfy all query conditions, if the array is "messages" then query would be:
Leaving this comment in case others come across similar problem and realize they should use $elemMatch (which can properly constrain index bounds of the query on both sides). | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Comment by David Storch [ 14/Oct/15 ] | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
robiii, glad I could help. We do have a page with basic documentation on MongoDB query optimization: http://docs.mongodb.org/manual/core/query-plans/ While tracking down this page, however, I discovered that it is a bit out of date and has some minor accuracies in its description of planning in 2.6.x and 3.0.x versions. I filed | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Comment by Rob Janssen [ 14/Oct/15 ] | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Hi David! Thanks for the explanation; it's really appreciated. I tried adding hints etc. but this didn't help. I understand now why because of your explanation which is, again, very much appreciated. EDIT
I wouldn't mind, maybe, a little more info on how the ranking works and how the best plan is selected but only if it's not too much of a bother. Maybe a pointer to the documentation if this can be found anywhere? Consider this issue solved and feel free to close it as resolved | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Comment by David Storch [ 14/Oct/15 ] | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Hi robiii, Thanks very much for filing this report. As you have discovered on your own, the problem you described was fixed in 3.0.7 under The issue has to do with index bounds selection for a multikey index. (A multikey index is an index which may have multiple index keys pointing to the same document in the collection, i.e. an indexed array field.) If there are multiple predicates over an array field, the server is only allowed to use one of these predicates to construct the index bounds. Consider the example of a collection containing the document {a: [1, 2, 3]} with index {a: 1}. The user issues the following query:
The document matches the query because array element "1" matches the predicate "a <= 1" and array element 3 matches the predicate "a >= 3". The system must answer this query either by
The problem query that you reported is essentially identical in structure to this toy example query. In your case, however, there is a large performance gap between the two plans. Imagine, for example, that the scan [3, Inf] is vastly more selective than the scan [-Inf, 1]. On version 2.2.0, you were getting lucky, since the system happened to choose the selective [3, Inf] plan. On version 3.0.6, you were getting equally unlucky, since the system happened to choose the unselective [-Inf, 1] plan. (If you're curious why this changed, it's because of a large query system refactor first released in version 2.6.0. Part of this refactor involves sorting the parsed query tree, which changes which predicate we happen to select to build the multikey index bounds.) In 3.0.7, the problem is fixed by I hope this explanation clears things up. Feel free to reach out with any further questions or concerns. Best, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Comment by Rob Janssen [ 14/Oct/15 ] | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
NO WAY! I just noticed that 3.0.7 was released yesterday (we installed 3.0.6 <24h ago, which was at the time the latest production version on mongodb.org). I installed 3.0.7 and guess what? It's fixed (or at least: seems to be; the query performs fine now)! I have glanced over the issues fixed in 3.0.7 and from what I found so far it seems that For those interested, the explain now looks like this:
Also please note that, in this comment but also previous comments and/or the issue itself, that wherever you read "2015-10-...00Z" you should actually read ISODate("2015-10...00Z"); I had this removed because my formatter doesn't like it | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Comment by Rob Janssen [ 14/Oct/15 ] | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Oh, also this doesn't improve/change the situation:
instead of:
|