From b53c51ff41801270ce02c1c38118a74e6f4cdc59 Mon Sep 17 00:00:00 2001 From: "3058078489@qq.com" <3058078489@qq.com> Date: Thu, 8 Jun 2023 12:14:49 +0800 Subject: [PATCH 1/3] remove repeat contain index from the relevant candidate indexes, this can avoid some useless calculations. --- src/mongo/db/query/planner_ixselect.cpp | 98 +++++++++++++++++++++++++ src/mongo/db/query/planner_ixselect.h | 12 +++ src/mongo/db/query/query_planner.cpp | 9 +++ 3 files changed, 119 insertions(+) diff --git a/src/mongo/db/query/planner_ixselect.cpp b/src/mongo/db/query/planner_ixselect.cpp index 307b8ef0a899d..e82981db85de7 100644 --- a/src/mongo/db/query/planner_ixselect.cpp +++ b/src/mongo/db/query/planner_ixselect.cpp @@ -49,6 +49,7 @@ #include "mongo/db/query/planner_wildcard_helpers.h" #include "mongo/db/query/query_planner_common.h" #include "mongo/logv2/log.h" +#include "mongo/bson/simple_bsonelement_comparator.h" namespace mongo { @@ -309,6 +310,103 @@ std::vector QueryPlannerIXSelect::findIndexesByHint( return out; } +// remove repeat contain index from the relevant candidate indexes, this can avoid some useless calculations. +// for example: +// {a:1, b:1} contain {a:1}, so we can remove index {a:1} from the candidates +// {a:"hashed", b:1} contain {a:"hashed"}, so we can remove index {a:"hahsed"} from the candidates +// +// {a:1, b:1} is better than {a:1},because both cases are satisfied for db.collection.find({a:xx}) +// and db.collection.find({a:xx,b:xx}) +// +void QueryPlannerIXSelect::removeRepeatContainIndexes(std::vector& allIndices) { + if (allIndices.size() <= 1) + return; + + auto isSpecialIndex = [](auto& it) { + if (it->type != INDEX_BTREE && it->type != INDEX_HASHED) { + return true; + } + + if (it->sparse || it->unique) { + return true; + } + + if (it->collator) { + return true; + } + + if (it->filterExpr) { + return true; + } + + BSONElement e = it->infoObj[IndexDescriptor::kExpireAfterSecondsFieldName]; + if (e.isNumber() == false) { + return false; + } + + auto expireTime = e.number(); + if (expireTime >= 0) { + return true; + } else { + return false; + } + }; + + auto dealKeyPattern = [](BSONObj& indexKeyPattern) { + BSONObjBuilder build; + BSONObjIterator kpIt(indexKeyPattern); + while (kpIt.more()) { + BSONElement elt = kpIt.next(); + if (elt.type() == mongo::String) { + build.append(elt.fieldName(), elt.String()); + continue; + } + + // The canonical check as to whether a key pattern element is "ascending" or "descending" is + // (elt.number() >= 0). This is defined by the Ordering class. + invariant(elt.isNumber()); + int sortOrder = (elt.number() >= 0) ? 1 : -1; + build.append(elt.fieldName(), sortOrder); + } + + return build.obj(); + }; + + for (auto iterator1 = allIndices.begin(); iterator1 != allIndices.end();) { + if (isSpecialIndex(iterator1) == true) { + ++iterator1; + continue; + } + + BSONObj keyPattern1 = dealKeyPattern((*iterator1).keyPattern); + + bool eraseIterator1 = false; + auto iterator2 = iterator1; + ++iterator2; + while (iterator2 != allIndices.end()) { + if (isSpecialIndex(iterator2) == true) { + ++iterator2; + continue; + } + + BSONObj keyPattern2 = dealKeyPattern((*iterator2).keyPattern); + + if (keyPattern2.isPrefixOf(keyPattern1, SimpleBSONElementComparator::kInstance)) { + iterator2 = allIndices.erase(iterator2); + } else if (keyPattern1.isPrefixOf(keyPattern2, SimpleBSONElementComparator::kInstance)) { + iterator1 = allIndices.erase(iterator1); + eraseIterator1 = true; + break; + } else { + ++iterator2; + } + } + + if (eraseIterator1 == false) + iterator1++; + } +} + // static std::vector QueryPlannerIXSelect::findRelevantIndices( const RelevantFieldIndexMap& fields, const std::vector& allIndices) { diff --git a/src/mongo/db/query/planner_ixselect.h b/src/mongo/db/query/planner_ixselect.h index 60a0b941c4603..d1ce9173b19f0 100644 --- a/src/mongo/db/query/planner_ixselect.h +++ b/src/mongo/db/query/planner_ixselect.h @@ -75,6 +75,18 @@ class QueryPlannerIXSelect { static std::vector findIndexesByHint(const BSONObj& hintedIndex, const std::vector& allIndices); + /** + * remove repeat contain index from the relevant candidate indexes, this can avoid some useless calculations. + * for example: + * {a:1, b:1} contain {a:1}, so we can remove index {a:1} from the candidates + * {a:"hashed", b:1} contain {a:"hashed"}, so we can remove index {a:"hahsed"} from the candidates + * + * {a:1, b:1} is better than {a:1},because both cases are satisfied for db.collection.find({a:xx}) + * and db.collection.find({a:xx,b:xx}) + */ + static void removeRepeatContainIndexes(std::vector& indexes); + + /** * Finds all indices prefixed by fields we have predicates over. Only these indices are * useful in answering the query. diff --git a/src/mongo/db/query/query_planner.cpp b/src/mongo/db/query/query_planner.cpp index 2a54c61f4cee6..c88f61110e446 100644 --- a/src/mongo/db/query/query_planner.cpp +++ b/src/mongo/db/query/query_planner.cpp @@ -776,6 +776,15 @@ StatusWith>> QueryPlanner::plan( "index"_attr = relevantIndices[i].toString()); } + QueryPlannerIXSelect::removeRepeatContainIndexes(relevantIndices); + for (size_t i = 0; i < relevantIndices.size(); ++i) { + LOGV2_DEBUG(20971, + 2, + "After Remove Repeat Contain Btree And Hashed Index, Relevant index", + "indexNumber"_attr = i, + "index"_attr = relevantIndices[i].toString()); + } + // Figure out how useful each index is to each predicate. QueryPlannerIXSelect::rateIndices(query.root(), "", relevantIndices, query.getCollator()); QueryPlannerIXSelect::stripInvalidAssignments(query.root(), relevantIndices); From 1422aba25fea24173f923099d167106d72911c19 Mon Sep 17 00:00:00 2001 From: "3058078489@qq.com" <3058078489@qq.com> Date: Thu, 8 Jun 2023 14:02:15 +0800 Subject: [PATCH 2/3] if hinted index, we should not to remove repeat contain index from the relevant candidate indexes --- src/mongo/db/query/query_planner.cpp | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/src/mongo/db/query/query_planner.cpp b/src/mongo/db/query/query_planner.cpp index c88f61110e446..a3d6a53112667 100644 --- a/src/mongo/db/query/query_planner.cpp +++ b/src/mongo/db/query/query_planner.cpp @@ -776,13 +776,15 @@ StatusWith>> QueryPlanner::plan( "index"_attr = relevantIndices[i].toString()); } - QueryPlannerIXSelect::removeRepeatContainIndexes(relevantIndices); - for (size_t i = 0; i < relevantIndices.size(); ++i) { - LOGV2_DEBUG(20971, - 2, - "After Remove Repeat Contain Btree And Hashed Index, Relevant index", - "indexNumber"_attr = i, - "index"_attr = relevantIndices[i].toString()); + if (!hintedIndexEntry) { + QueryPlannerIXSelect::removeRepeatContainIndexes(relevantIndices); + for (size_t i = 0; i < relevantIndices.size(); ++i) { + LOGV2_DEBUG(20971, + 2, + "After Remove Repeat Contain Btree And Hashed Index, Relevant index", + "indexNumber"_attr = i, + "index"_attr = relevantIndices[i].toString()); + } } // Figure out how useful each index is to each predicate. From 7b9822c96cf3a235afce1b21a536c005a1b81614 Mon Sep 17 00:00:00 2001 From: "3058078489@qq.com" <3058078489@qq.com> Date: Tue, 20 Jun 2023 20:25:48 +0800 Subject: [PATCH 3/3] renew planner_ixselect --- src/mongo/db/query/planner_ixselect.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/mongo/db/query/planner_ixselect.cpp b/src/mongo/db/query/planner_ixselect.cpp index e82981db85de7..dcf6006462d74 100644 --- a/src/mongo/db/query/planner_ixselect.cpp +++ b/src/mongo/db/query/planner_ixselect.cpp @@ -380,7 +380,7 @@ void QueryPlannerIXSelect::removeRepeatContainIndexes(std::vector& a BSONObj keyPattern1 = dealKeyPattern((*iterator1).keyPattern); - bool eraseIterator1 = false; + bool eraseIterator = false; auto iterator2 = iterator1; ++iterator2; while (iterator2 != allIndices.end()) { @@ -395,14 +395,14 @@ void QueryPlannerIXSelect::removeRepeatContainIndexes(std::vector& a iterator2 = allIndices.erase(iterator2); } else if (keyPattern1.isPrefixOf(keyPattern2, SimpleBSONElementComparator::kInstance)) { iterator1 = allIndices.erase(iterator1); - eraseIterator1 = true; + eraseIterator = true; break; } else { ++iterator2; } } - if (eraseIterator1 == false) + if (eraseIterator == false) iterator1++; } }