summaryrefslogtreecommitdiff
path: root/src/mongo/db/query/planner_ixselect.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/mongo/db/query/planner_ixselect.cpp')
-rw-r--r--src/mongo/db/query/planner_ixselect.cpp67
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