summaryrefslogtreecommitdiff
path: root/src/mongo/db/query/plan_ranker_index_prefix_test.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/mongo/db/query/plan_ranker_index_prefix_test.cpp')
-rw-r--r--src/mongo/db/query/plan_ranker_index_prefix_test.cpp422
1 files changed, 0 insertions, 422 deletions
diff --git a/src/mongo/db/query/plan_ranker_index_prefix_test.cpp b/src/mongo/db/query/plan_ranker_index_prefix_test.cpp
deleted file mode 100644
index ae3a5455863..00000000000
--- a/src/mongo/db/query/plan_ranker_index_prefix_test.cpp
+++ /dev/null
@@ -1,422 +0,0 @@
-/**
- * Copyright (C) 2023-present MongoDB, Inc.
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the Server Side Public License, version 1,
- * as published by MongoDB, Inc.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * Server Side Public License for more details.
- *
- * You should have received a copy of the Server Side Public License
- * along with this program. If not, see
- * <http://www.mongodb.com/licensing/server-side-public-license>.
- *
- * As a special exception, the copyright holders give permission to link the
- * code of portions of this program with the OpenSSL library under certain
- * conditions as described in each individual source file and distribute
- * linked combinations including the program with the OpenSSL library. You
- * must comply with the Server Side Public License in all respects for
- * all of the code used other than as permitted herein. If you modify file(s)
- * with this exception, you may extend this exception to your version of the
- * file(s), but you are not obligated to do so. If you do not wish to do so,
- * delete this exception statement from your version. If you delete this
- * exception statement from all source files in the program, then also delete
- * it in the license file.
- */
-
-/**
- * This file contains tests for mongo/db/query/plan_ranker.h
- */
-
-#include "mongo/db/query/plan_ranker.h"
-
-#include "mongo/unittest/unittest.h"
-
-namespace mongo::plan_ranker {
-namespace {
-IndexEntry buildSimpleIndexEntry(const BSONObj& kp) {
- return {kp,
- IndexNames::nameToType(IndexNames::findPluginName(kp)),
- IndexDescriptor::kLatestIndexVersion,
- false,
- {},
- {},
- false,
- false,
- CoreIndexInfo::Identifier("test_foo"),
- nullptr,
- {},
- nullptr,
- nullptr};
-}
-
-OrderedIntervalList makeOIL(const std::string& fieldName,
- std::initializer_list<BSONObj> intervals) {
- OrderedIntervalList oil(fieldName);
- for (auto&& interval : intervals) {
- oil.intervals.emplace_back(std::move(interval), true, true);
- }
- return oil;
-}
-
-std::unique_ptr<QuerySolution> makeSolution(std::unique_ptr<QuerySolutionNode> child) {
- auto solution = std::make_unique<QuerySolution>();
- solution->setRoot(std::make_unique<FetchNode>(std::move(child)));
- return solution;
-}
-
-std::unique_ptr<IndexScanNode> makeIndexScan(
- BSONObj indexKey, std::initializer_list<OrderedIntervalList> indexBoundsFields) {
- IndexBounds bounds{};
- for (auto&& field : indexBoundsFields) {
- bounds.fields.emplace_back(std::move(field));
- }
-
- auto indexScan = std::make_unique<IndexScanNode>(buildSimpleIndexEntry(indexKey));
- indexScan->bounds = std::move(bounds);
- indexScan->computeProperties();
-
- return indexScan;
-}
-} // namespace
-
-TEST(IndexPrefixHeuristicTest, SingleIndexScan_LongerSinglePointPrefixWins) {
- // a: [[1, 1]]; b: [[1, 3]]
- auto indexScan1 = makeIndexScan(BSON("a" << 1 << "b" << 1),
- {
- makeOIL("a", {BSON("" << 1 << "" << 1)}),
- makeOIL("b", {BSON("" << 1 << "" << 3)}),
- });
- auto solution1 = makeSolution(std::move(indexScan1));
-
- // c: [[1, 1]]; d: [[1, 1]]
- auto indexScan2 = makeIndexScan(BSON("c" << 1 << "d" << 1),
- {
- makeOIL("c", {BSON("" << 1 << "" << 1)}),
- makeOIL("d", {BSON("" << 1 << "" << 1)}),
- });
- auto solution2 = makeSolution(std::move(indexScan2));
-
- // e: [[1, 1]]; f: [[2, 2], [3, 3]]; g: [[4, 4]]
- auto indexScan3 =
- makeIndexScan(BSON("e" << 1 << "f" << 1 << "g" << 1),
- {
- makeOIL("e", {BSON("" << 1 << "" << 1)}),
- makeOIL("f", {BSON("" << 2 << "" << 2), BSON("" << 3 << "" << 3)}),
- makeOIL("g", {BSON("" << 4 << "" << 4)}),
- });
- auto solution3 = makeSolution(std::move(indexScan3));
-
- std::vector<const QuerySolution*> solutions{solution1.get(), solution2.get(), solution3.get()};
- auto winners = applyIndexPrefixHeuristic(solutions);
- ASSERT_EQ(1, winners.size());
- ASSERT_EQ(1, winners[0]);
-}
-
-TEST(IndexPrefixHeuristicTest, SingleIndexScan_LongerPointPrefixWins) {
- // a: [[1, 1], [2, 2]]; b: [[1, 3]]
- auto indexScan1 =
- makeIndexScan(BSON("a" << 1 << "b" << 1),
- {
- makeOIL("a", {BSON("" << 1 << "" << 1), BSON("" << 2 << "" << 2)}),
- makeOIL("b", {BSON("" << 1 << "" << 3)}),
- });
- auto solution1 = makeSolution(std::move(indexScan1));
-
- // c: [[1, 1], [2, 2]]; d: [[1, 1], [3, 3]], e: [[1, 1]]
- auto indexScan2 =
- makeIndexScan(BSON("c" << 1 << "d" << 1 << "e" << 1),
- {
- makeOIL("c", {BSON("" << 1 << "" << 1), BSON("" << 2 << "" << 2)}),
- makeOIL("d", {BSON("" << 1 << "" << 1), BSON("" << 3 << "" << 3)}),
- makeOIL("e", {BSON("" << 1 << "" << 1)}),
- });
- auto solution2 = makeSolution(std::move(indexScan2));
-
- std::vector<const QuerySolution*> solutions{solution1.get(), solution2.get()};
- auto winners = applyIndexPrefixHeuristic(solutions);
- ASSERT_EQ(1, winners.size());
- ASSERT_EQ(1, winners[0]);
-}
-
-TEST(IndexPrefixHeuristicTest, SingleIndexScan_ClosedIntervalPrefixWins) {
- // a: [[1, 1], [2, 2]]; b: [[1, MaxKey]]
- auto indexScan1 =
- makeIndexScan(BSON("a" << 1 << "b" << 1),
- {
- makeOIL("a", {BSON("" << 1 << "" << 1), BSON("" << 2 << "" << 2)}),
- makeOIL("b", {BSON("" << 1 << "" << MAXKEY)}),
- });
- auto solution1 = makeSolution(std::move(indexScan1));
-
- // c: [[1, 1], [2, 2]]; d: [[1, 3]]
- auto indexScan2 =
- makeIndexScan(BSON("c" << 1 << "d" << 1 << "e" << 1),
- {
- makeOIL("c", {BSON("" << 1 << "" << 1), BSON("" << 2 << "" << 2)}),
- makeOIL("b", {BSON("" << 1 << "" << 3)}),
- });
- auto solution2 = makeSolution(std::move(indexScan2));
-
- std::vector<const QuerySolution*> solutions{solution1.get(), solution2.get()};
- auto winners = applyIndexPrefixHeuristic(solutions);
- ASSERT_EQ(1, winners.size());
- ASSERT_EQ(1, winners[0]);
-}
-
-TEST(IndexPrefixHeuristicTest, SingleIndexScan_LongerPrefixWins) {
- // a: [[2, 3]]; b: [[1, 1]]
- auto indexScan1 = makeIndexScan(BSON("a" << 1 << "b" << 1),
- {
- makeOIL("a", {BSON("" << 2 << "" << 3)}),
- makeOIL("b", {BSON("" << 1 << "" << 1)}),
- });
- auto solution1 = makeSolution(std::move(indexScan1));
-
- // c: [[5, 10]]; d: [[10, 20]], e: [[1, 101]]
- auto indexScan2 = makeIndexScan(BSON("c" << 1 << "d" << 1 << "e" << 1),
- {
- makeOIL("c", {BSON("" << 5 << "" << 10)}),
- makeOIL("d", {BSON("" << 10 << "" << 20)}),
- makeOIL("e", {BSON("" << 1 << "" << 101)}),
- });
- auto solution2 = makeSolution(std::move(indexScan2));
-
- std::vector<const QuerySolution*> solutions{solution1.get(), solution2.get()};
- auto winners = applyIndexPrefixHeuristic(solutions);
- ASSERT_EQ(1, winners.size());
- ASSERT_EQ(1, winners[0]);
-}
-
-TEST(IndexPrefixHeuristicTest, SingleIndexScan_MultipleWinners) {
- // a: [[2, 2]]; b: [[1, 1]]
- auto indexScan1 = makeIndexScan(BSON("a" << 1 << "b" << 1),
- {
- makeOIL("a", {BSON("" << 2 << "" << 2)}),
- makeOIL("b", {BSON("" << 1 << "" << 1)}),
- });
- auto solution1 = makeSolution(std::move(indexScan1));
-
- // c: [[5, 5]]; d: [[10, 20]]
- auto indexScan2 = makeIndexScan(BSON("c" << 1 << "d" << 1),
- {
- makeOIL("c", {BSON("" << 5 << "" << 5)}),
- makeOIL("d", {BSON("" << 10 << "" << 10)}),
- });
- auto solution2 = makeSolution(std::move(indexScan2));
-
- std::vector<const QuerySolution*> solutions{solution1.get(), solution2.get()};
- auto winners = applyIndexPrefixHeuristic(solutions);
- ASSERT_EQ(2, winners.size());
-}
-
-TEST(IndexPrefixHeuristicTest, SingleIndexScan_ShortestIndexKeyWins) {
- // a: [[2, 2]]; b: [[MinKey, MaxKey]]
- auto indexScan1 = makeIndexScan(BSON("a" << 1 << "b" << 1),
- {
- makeOIL("a", {BSON("" << 2 << "" << 2)}),
- makeOIL("b", {BSON("" << MINKEY << "" << MAXKEY)}),
- });
- auto solution1 = makeSolution(std::move(indexScan1));
-
- // c: [[5, 5]]
- auto indexScan2 = makeIndexScan(BSON("c" << 1),
- {
- makeOIL("c", {BSON("" << 5 << "" << 5)}),
- });
- auto solution2 = makeSolution(std::move(indexScan2));
-
- std::vector<const QuerySolution*> solutions{solution1.get(), solution2.get()};
- auto winners = applyIndexPrefixHeuristic(solutions);
- ASSERT_EQ(1, winners.size());
- ASSERT_EQ(1, winners[0]);
-}
-
-TEST(IndexPrefixHeuristicTest, SingleIndexScan_DifferentQueryShapesNoWin) {
- // FETCH <- INDEX_SCAN
- auto indexScan =
- makeIndexScan(BSON("a" << 1 << "b" << 1),
- {
- makeOIL("a", {BSON("" << 1 << "" << 1), BSON("" << 2 << "" << 2)}),
- makeOIL("b", {BSON("" << 1 << "" << 3)}),
- });
- auto solution1 = makeSolution(std::move(indexScan));
-
- // FETCH <- COLLECTION_SCAN
- auto collScan = std::make_unique<CollectionScanNode>();
- auto solution2 = makeSolution(std::move(collScan));
-
- std::vector<const QuerySolution*> solutions{solution1.get(), solution2.get()};
- auto winners = applyIndexPrefixHeuristic(solutions);
- ASSERT_EQ(0, winners.size());
-}
-
-
-TEST(IndexPrefixHeuristicTest, UnionIndexScan_ShortestIndexKeyWins) {
- auto orNode1 = std::make_unique<OrNode>();
- {
- // a: [[2, 2]]; b: [[1, 1]]
- auto indexScan1 = makeIndexScan(BSON("a" << 1 << "b" << 1),
- {
- makeOIL("a", {BSON("" << 2 << "" << 3)}),
- makeOIL("b", {BSON("" << 1 << "" << 1)}),
- });
-
- // c: [[2, 2]], d: [[MaxKey, MinKey]]
- auto indexScan2 = makeIndexScan(BSON("c" << 1 << "d" << 1),
- {
- makeOIL("c", {BSON("" << 2 << "" << 2)}),
- makeOIL("d", {BSON("" << MAXKEY << "" << MINKEY)}),
- });
- orNode1->children.emplace_back(indexScan1.release());
- orNode1->children.emplace_back(indexScan2.release());
- }
- auto solution1 = makeSolution(std::move(orNode1));
-
- auto orNode2 = std::make_unique<OrNode>();
- {
- // a: [[2, 2]]; b: [[1, 1]]
- auto indexScan1 = makeIndexScan(BSON("a" << 1 << "b" << 1),
- {
- makeOIL("a", {BSON("" << 2 << "" << 3)}),
- makeOIL("b", {BSON("" << 1 << "" << 1)}),
- });
-
- // c: [[2, 2]]
- auto indexScan2 = makeIndexScan(BSON("c" << 1),
- {
- makeOIL("c", {BSON("" << 2 << "" << 2)}),
- });
- orNode2->children.emplace_back(indexScan1.release());
- orNode2->children.emplace_back(indexScan2.release());
- }
- auto solution2 = makeSolution(std::move(orNode2));
-
- std::vector<const QuerySolution*> solutions{solution1.get(), solution2.get()};
- auto winners = applyIndexPrefixHeuristic(solutions);
- ASSERT_EQ(1, winners.size());
- ASSERT_EQ(1, winners[0]);
-}
-
-TEST(IndexPrefixHeuristicTest, UnionIndexScan_MultipleWinners) {
- auto orNode1 = std::make_unique<OrNode>();
- {
- // a: [[2, 2]]; b: [[1, 1]]
- auto indexScan1 = makeIndexScan(BSON("a" << 1 << "b" << 1),
- {
- makeOIL("a", {BSON("" << 2 << "" << 3)}),
- makeOIL("b", {BSON("" << 1 << "" << 1)}),
- });
-
- // c: [[2, 2]]
- auto indexScan2 = makeIndexScan(BSON("c" << 1),
- {
- makeOIL("c", {BSON("" << 2 << "" << 2)}),
- });
- orNode1->children.emplace_back(indexScan1.release());
- orNode1->children.emplace_back(indexScan2.release());
- }
- auto solution1 = makeSolution(std::move(orNode1));
-
- auto orNode2 = std::make_unique<OrNode>();
- {
- // a: [[2, 2]]; b: [[1, 1]]
- auto indexScan1 = makeIndexScan(BSON("a" << 1 << "b" << 1),
- {
- makeOIL("a", {BSON("" << 2 << "" << 3)}),
- makeOIL("b", {BSON("" << 1 << "" << 1)}),
- });
-
- // c: [[2, 2]], d: [[MaxKey, MinKey]]
- auto indexScan2 = makeIndexScan(BSON("c" << 1 << "d" << 1),
- {
- makeOIL("c", {BSON("" << 2 << "" << 2)}),
- makeOIL("d", {BSON("" << MAXKEY << "" << MINKEY)}),
- });
- orNode2->children.emplace_back(indexScan1.release());
- orNode2->children.emplace_back(indexScan2.release());
- }
- auto solution2 = makeSolution(std::move(orNode2));
-
- auto orNode3 = std::make_unique<OrNode>();
- {
- // a: [[2, 2]]; b: [[1, 1]]
- auto indexScan1 = makeIndexScan(BSON("a" << 1 << "b" << 1),
- {
- makeOIL("a", {BSON("" << 2 << "" << 3)}),
- makeOIL("b", {BSON("" << 1 << "" << 1)}),
- });
-
- // c: [[2, 2]]
- auto indexScan2 = makeIndexScan(BSON("c" << 1),
- {
- makeOIL("c", {BSON("" << 2 << "" << 2)}),
- });
- orNode3->children.emplace_back(indexScan1.release());
- orNode3->children.emplace_back(indexScan2.release());
- }
- auto solution3 = makeSolution(std::move(orNode3));
-
- std::vector<const QuerySolution*> solutions{solution1.get(), solution2.get(), solution3.get()};
- auto winners = applyIndexPrefixHeuristic(solutions);
- ASSERT_EQ(2, winners.size());
- ASSERT_EQ(0, winners[0]);
- ASSERT_EQ(2, winners[1]);
-}
-
-TEST(IndexPrefixHeuristicTest, UnionIndexScan_DifferentQueryShapeNoWin) {
- auto orNode1 = std::make_unique<OrNode>();
- {
- // a: [[2, 2]]; b: [[1, 1]]
- auto indexScan1 = makeIndexScan(BSON("a" << 1 << "b" << 1),
- {
- makeOIL("a", {BSON("" << 2 << "" << 3)}),
- makeOIL("b", {BSON("" << 1 << "" << 1)}),
- });
-
- // c: [[2, 2]], d: [[MaxKey, MinKey]]
- auto indexScan2 = makeIndexScan(BSON("c" << 1 << "d" << 1),
- {
- makeOIL("c", {BSON("" << 2 << "" << 2)}),
- makeOIL("d", {BSON("" << MAXKEY << "" << MINKEY)}),
- });
- orNode1->children.emplace_back(indexScan1.release());
- orNode1->children.emplace_back(indexScan2.release());
- }
- auto solution1 = makeSolution(std::move(orNode1));
-
- auto orNode2 = std::make_unique<OrNode>();
- {
- // a: [[2, 2]]; b: [[1, 1]]
- auto indexScan1 = makeIndexScan(BSON("a" << 1 << "b" << 1),
- {
- makeOIL("a", {BSON("" << 2 << "" << 3)}),
- makeOIL("b", {BSON("" << 1 << "" << 1)}),
- });
-
- // c: [[2, 2]], d: [[MaxKey, MinKey]]
- auto indexScan2 = makeIndexScan(BSON("c" << 1 << "d" << 1),
- {
- makeOIL("c", {BSON("" << 2 << "" << 2)}),
- makeOIL("d", {BSON("" << MAXKEY << "" << MINKEY)}),
- });
-
- // e: [[2, 2]]
- auto indexScan3 = makeIndexScan(BSON("e" << 1),
- {
- makeOIL("e", {BSON("" << 2 << "" << 2)}),
- });
- orNode2->children.emplace_back(indexScan1.release());
- orNode2->children.emplace_back(indexScan2.release());
- orNode2->children.emplace_back(indexScan3.release());
- }
- auto solution2 = makeSolution(std::move(orNode2));
-
- std::vector<const QuerySolution*> solutions{solution1.get(), solution2.get()};
- auto winners = applyIndexPrefixHeuristic(solutions);
- ASSERT_EQ(0, winners.size());
-}
-} // namespace mongo::plan_ranker