-
-
Notifications
You must be signed in to change notification settings - Fork 507
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[WIP] Compound Indexes #812
Conversation
I had way less time than I expected but finally this is finished :) |
Not finished, will write why in doctrine/mongodb#154 |
I've added IndexChecker class with logic ported from doctrine/mongodb#154, also added new methods to FieldExtractor and covered them with tests. Still need to rewrite tests from doctrine/mongodb#154 for IndexChecker and add new ones covering $or clauses behavior |
…entIndexes option
* @param \Doctrine\MongoDB\Collection $collection | ||
* @param boolean $allowLessEfficientIndexes | ||
*/ | ||
public function __construct(Query $query, Collection $collection, $allowLessEfficientIndexes = true) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Shame on PHP for no friendly classes
Thank you for all your hard work! I left a few line notes after looking over it. |
…return boolean, updated some missed phpdocs
$orClauses = $this->query->getFieldExtractor()->getOrClauses(); | ||
foreach ($orClauses as $or) { | ||
$orExtractor = new FieldExtractor($or); | ||
if (!$this->getIndexesIncludingFields($orExtractor->getFields(), true)) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why does the $or
clause inspection use true
for $findAny
, while handling of the main query does not?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah, it looks like it's because you're just checking if at least one index exists.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Exactly, I don't need to check anything more for $or
so just knowing that there is index is enough :)
@malarzm: Can you elaborate on "fixed issue was a bug but introduced changes might be worth a note in CHANGELOG", which is the outstanding todo item in the PR description? |
@jmikola: I'm not sure right now what exactly I had in mind at the time... probably that Exception messages has changed (and that I wanted to change |
It it's just a matter of exception messages changing (and not the class), I don't think there's a problem. Feel free to remove the todo item. |
Removed |
return $index; | ||
} else { | ||
$matchingIndexes[] = $index; | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think you would want to continue
after this, as the foreach
below is redundant. We've already matched an index (possibly less efficient) by this point, so there is nothing left to do. I'm having difficulty tracking the entire code flow, but is there a chance we might add the index to $matchingIndexes
twice with the code as-is?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You're right about this one
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Line wasn't changed but issue is fixed along with removing allowLessEfficientIndexes
After giving this PR some more thought, I have more new feedback:
I think the motivation behind the enforcement level where Originally in #761, @dwieeb's bug report was that the index checker was giving a false positive by not respecting the field order (e.g. ODM would assume Lastly, we should consider how this PR will work with special index types such as geo-spatial and full-text. Those are also cases where even a single-field geo-spatial or full-text index could prove to be very selective even if the query includes other fields. For instance, if the geo-spatial index can narrow the number of documents we must consider to one, the cost of checking the additional fields in our query is fairly negligible. On a side note, a great way to require indexes at the server level is the |
private function getIndexesIncludingFields($fieldsNames, $findAny = false) | ||
{ | ||
$matchingIndexes = array(); | ||
$indexes = $this->collection->getIndexInfo(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This ends up doing a round-trip to the database server, as it needs to query the system.indexes
collection. I realize that is the only authoritative way to determine which indexes are in MongoDB, but the ODM might be better served by relying on the indexes defined in ClassMetadata (and we should be clear about that documentation).
In a production deployment, the overhead of this round-trip is undesirable and users should be expected to ensure that the indexes in their metadata are synced with the database (the schema update command does this).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
👍
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
👍 but also I think whole requireIndexes()
is undesirable behavior in production and should be considered dev feature (maybe it's worth pointing this out in docs as well?) - I'd rather have slow query than 500 page :)
As for text indexes: right now Last (in self defense) this PR as you said goes further than original bug report required but I thought it was worth it (and also was great opportunity for me to learn few things :) ) I'll update TODO list with everything pointed out. |
I definitely understood the intent of The MongoDB documentation you cited makes a solid point and those indexes generally will be more efficient; however, I just had reservations about it being an option for ODM to enforce, since we really don't have enough information to say what's most efficient based on the index specs alone (we should trust MongoDB's internal query optimizer for that :)
That issue is just to add query builder helper methods, but the Regarding the geo-spatial and text index support, I would suggest removing |
Note: the index intersection provided in MongoDB 2.6+ is another thing to consider (also covered in this blog post). Two single-field indexes might now be used together to handle a single query, essentially fulfilling the role of a compound index. That would be another argument for relaxing the index checks in this PR. |
Yup I have to agree it'll simplify everything now. One question though:
According to this section of doc Mongo can intersect single-field index with Compound Indexes prefixes and I guess it's also capable of intersecting two Compound Indexes? If so then maintaining `allowLessEfficientIndexes`` would be a nightmare and I'm glad they are about to be removed :D Btw this feature is now added to TODO list |
My understanding is that compound indexes can be intersected, but obviously with respect to their prefixes (field ordering). Geo-spatial and text indexes currently don't support intersection, but that is expected to change down the road. |
Ok, thanks for confirmation, I'll sleep with this and will try to figure out a way to implement it |
@jmikola @jwage I'm having troubles with utilizing
Do you have any thoughts on this? |
@malarzm: I don't have time to look into this within the next week; I'll have to come back to it afterwards. At a quick glance, working around the |
No problem, I hadn't much time either. I was thinking that it's done for On Wed, Jun 18, 2014 at 10:56 PM, Jeremy Mikola notifications@github.com
|
For the moment being I'm more in favour of dropping |
Fixes #761
, depends on doctrine/mongodb#154Exceptions I have left Query::getUnindexedFields untouched and adjusted Exception Message (instead of showing unindexed fields there's a list of used ones. I was thinking about comparing existing indexes with fields from query and suggesting developer fields to add/remove to query to match index requiring least changes but finally gave up on this - however if you think it's good idea I'll implement it)
TODO:
AFTER REVIEW:
allowLessEfficientIndexes
feature (including docs)ClassMetadata
instead of DB (code & docs)cc @dwieeb