diff options
author | David Storch <david.storch@10gen.com> | 2015-01-09 14:20:37 -0500 |
---|---|---|
committer | David Storch <david.storch@10gen.com> | 2015-01-16 17:13:32 -0500 |
commit | c3da2fc6642f143111d104c871f420d523f949b5 (patch) | |
tree | 830de681c8759e9d7cbdc6ec4b055dfa5c6bf947 /src/mongo/db/query/planner_ixselect.cpp | |
parent | 020cc851f48cca51ba2ac6c94ca93119a4563c4f (diff) | |
download | mongo-c3da2fc6642f143111d104c871f420d523f949b5.tar.gz |
SERVER-15802 if an equality over a single-field unique index can be used to index an AND, ignore all other indices
Diffstat (limited to 'src/mongo/db/query/planner_ixselect.cpp')
-rw-r--r-- | src/mongo/db/query/planner_ixselect.cpp | 67 |
1 files changed, 67 insertions, 0 deletions
diff --git a/src/mongo/db/query/planner_ixselect.cpp b/src/mongo/db/query/planner_ixselect.cpp index f00231aee5b..024830399a4 100644 --- a/src/mongo/db/query/planner_ixselect.cpp +++ b/src/mongo/db/query/planner_ixselect.cpp @@ -379,6 +379,73 @@ namespace mongo { } } + namespace { + + /** + * For every node in the subtree rooted at 'node' that has a RelevantTag, removes index + * assignments from that tag. + * + * Used as a helper for stripUnneededAssignments(). + */ + void clearAssignments(MatchExpression* node) { + if (node->getTag()) { + RelevantTag* rt = static_cast<RelevantTag*>(node->getTag()); + rt->first.clear(); + rt->notFirst.clear(); + } + + for (size_t i = 0; i < node->numChildren(); i++) { + clearAssignments(node->getChild(i)); + } + } + + } // namespace + + // static + void QueryPlannerIXSelect::stripUnneededAssignments(MatchExpression* node, + const std::vector<IndexEntry>& indices) { + if (MatchExpression::AND == node->matchType()) { + for (size_t i = 0; i < node->numChildren(); i++) { + MatchExpression* child = node->getChild(i); + + if (MatchExpression::EQ != child->matchType()) { + continue; + } + + if (!child->getTag()) { + continue; + } + + // We found a EQ child of an AND which is tagged. + RelevantTag* rt = static_cast<RelevantTag*>(child->getTag()); + + // Look through all of the indices for which this predicate can be answered with + // the leading field of the index. + for (std::vector<size_t>::const_iterator i = rt->first.begin(); + i != rt->first.end(); ++i) { + size_t index = *i; + + if (indices[index].unique && 1 == indices[index].keyPattern.nFields()) { + // Found an EQ predicate which can use a single-field unique index. + // Clear assignments from the entire tree, and add back a single assignment + // for 'child' to the unique index. + clearAssignments(node); + RelevantTag* newRt = static_cast<RelevantTag*>(child->getTag()); + newRt->first.push_back(index); + + // Tag state has been reset in the entire subtree at 'root'; nothing + // else for us to do. + return; + } + } + } + } + + for (size_t i = 0; i < node->numChildren(); i++) { + stripUnneededAssignments(node->getChild(i), indices); + } + } + // // Helpers used by stripInvalidAssignments // |