diff options
Diffstat (limited to 'src/mongo/db/query/planner_ixselect.cpp')
| -rw-r--r-- | src/mongo/db/query/planner_ixselect.cpp | 67 |
1 files changed, 30 insertions, 37 deletions
diff --git a/src/mongo/db/query/planner_ixselect.cpp b/src/mongo/db/query/planner_ixselect.cpp index 755077517af..518da370750 100644 --- a/src/mongo/db/query/planner_ixselect.cpp +++ b/src/mongo/db/query/planner_ixselect.cpp @@ -245,7 +245,7 @@ static bool boundsGeneratingNodeContainsComparisonToType(MatchExpression* node, // static void QueryPlannerIXSelect::getFields(const MatchExpression* node, string prefix, - RelevantFieldIndexMap* out) { + stdx::unordered_set<string>* out) { // Do not traverse tree beyond a NOR negation node MatchExpression::MatchType exprtype = node->matchType(); if (exprtype == MatchExpression::NOR) { @@ -254,12 +254,16 @@ void QueryPlannerIXSelect::getFields(const MatchExpression* node, // Leaf nodes with a path and some array operators. if (Indexability::nodeCanUseIndexOnOwnField(node)) { - bool supportSparse = Indexability::nodeSupportedBySparseIndex(node); - (*out)[prefix + node->path().toString()] = {supportSparse}; - } else if (Indexability::isBoundsGeneratingElemMatchObject(node)) { + out->insert(prefix + node->path().toString()); + } else if (Indexability::arrayUsesIndexOnChildren(node)) { // If the array uses an index on its children, it's something like // {foo : {$elemMatch: {bar: 1}}}, in which case the predicate is really over foo.bar. - prefix += node->path().toString() + "."; + // + // When we have {foo: {$all: [{$elemMatch: {a: 1}}], the path of the embedded elemMatch + // is empty. We don't want to append a dot in that case as the field would be foo..a. + if (!node->path().empty()) { + prefix += node->path().toString() + "."; + } for (size_t i = 0; i < node->numChildren(); ++i) { getFields(node->getChild(i), prefix, out); @@ -271,7 +275,8 @@ void QueryPlannerIXSelect::getFields(const MatchExpression* node, } } -void QueryPlannerIXSelect::getFields(const MatchExpression* node, RelevantFieldIndexMap* out) { +void QueryPlannerIXSelect::getFields(const MatchExpression* node, + stdx::unordered_set<string>* out) { getFields(node, "", out); } @@ -311,40 +316,26 @@ std::vector<IndexEntry> QueryPlannerIXSelect::findIndexesByHint( // static std::vector<IndexEntry> QueryPlannerIXSelect::findRelevantIndices( - const RelevantFieldIndexMap& fields, const std::vector<IndexEntry>& allIndices) { + const stdx::unordered_set<std::string>& fields, const std::vector<IndexEntry>& allIndices) { std::vector<IndexEntry> out; - for (auto&& index : allIndices) { - BSONObjIterator it(index.keyPattern); + for (auto&& entry : allIndices) { + BSONObjIterator it(entry.keyPattern); BSONElement elt = it.next(); - const std::string fieldName = elt.fieldNameStringData().toString(); - - // If the index is non-sparse we can use the field regardless its sparsity, otherwise we - // should find the field that can be answered by a sparse index. - if (fields.contains(fieldName) && - (!index.sparse || fields.find(fieldName)->second.isSparse)) { - out.push_back(index); + if (fields.end() != fields.find(elt.fieldName())) { + out.push_back(entry); } } return out; } -std::vector<IndexEntry> QueryPlannerIXSelect::expandIndexes(const RelevantFieldIndexMap& fields, - std::vector<IndexEntry> relevantIndices, - bool indexHinted) { +std::vector<IndexEntry> QueryPlannerIXSelect::expandIndexes( + const stdx::unordered_set<std::string>& fields, std::vector<IndexEntry> relevantIndices) { std::vector<IndexEntry> out; - // Filter out fields that cannot be answered by any sparse index. We know wildcard indexes are - // sparse, so we don't want to expand the wildcard index based on such fields. - stdx::unordered_set<std::string> sparseIncompatibleFields; - for (auto&& [fieldName, idxProperty] : fields) { - if (idxProperty.isSparse || indexHinted) { - sparseIncompatibleFields.insert(fieldName); - } - } for (auto&& entry : relevantIndices) { if (entry.type == IndexType::INDEX_WILDCARD) { - wcp::expandWildcardIndexEntry(entry, sparseIncompatibleFields, &out); + wcp::expandWildcardIndexEntry(entry, fields, &out); } else { out.push_back(std::move(entry)); } @@ -789,8 +780,7 @@ void QueryPlannerIXSelect::_rateIndices(MatchExpression* node, childRt->path = rt->path; node->getChild(0)->setTag(childRt); } - } else if (Indexability::arrayUsesIndexOnChildren(node) && !node->path().empty()) { - // Note we skip empty path components since they are not allowed in index key patterns. + } else if (Indexability::arrayUsesIndexOnChildren(node)) { const auto newPath = prefix + node->path().toString(); ElemMatchContext newContext; // Note this StringData is unowned and references the string declared on the stack here. @@ -801,7 +791,12 @@ void QueryPlannerIXSelect::_rateIndices(MatchExpression* node, // If the array uses an index on its children, it's something like // {foo: {$elemMatch: {bar: 1}}}, in which case the predicate is really over foo.bar. - prefix += node->path().toString() + "."; + // + // When we have {foo: {$all: [{$elemMatch: {a: 1}}], the path of the embedded elemMatch + // is empty. We don't want to append a dot in that case as the field would be foo..a. + if (!node->path().empty()) { + prefix += node->path().toString() + "."; + } for (size_t i = 0; i < node->numChildren(); ++i) { _rateIndices(node->getChild(i), prefix, indices, collator, newContext); } @@ -924,10 +919,7 @@ void QueryPlannerIXSelect::stripUnneededAssignments(MatchExpression* node, */ static void removeIndexRelevantTag(MatchExpression* node, size_t idx) { RelevantTag* tag = static_cast<RelevantTag*>(node->getTag()); - if (!tag) { - return; - } - + verify(tag); vector<size_t>::iterator firstIt = std::find(tag->first.begin(), tag->first.end(), idx); if (firstIt != tag->first.end()) { tag->first.erase(firstIt); @@ -952,8 +944,9 @@ void stripInvalidAssignmentsToPartialIndexNode(MatchExpression* node, size_t idxNo, const IndexEntry& idxEntry, bool inNegationOrElemMatchObj) { - removeIndexRelevantTag(node, idxNo); - + if (node->getTag()) { + removeIndexRelevantTag(node, idxNo); + } inNegationOrElemMatchObj |= nodeIsNegationOrElemMatchObj(node); for (size_t i = 0; i < node->numChildren(); ++i) { // If 'node' is an OR and our current clause satisfies the filter expression, then we may be |
