summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDenis Grebennicov <denis.grebennicov@mongodb.com>2022-05-04 17:39:02 +0000
committerEvergreen Agent <no-reply@evergreen.mongodb.com>2022-05-05 10:25:47 +0000
commit172385698678f8c9fb23f76ae028a446bd4c14b5 (patch)
treec955363d423e51146b417db87f17087b2c35ce92
parent728342e382a9f8b6f16513de92ba08815bebba0d (diff)
downloadmongo-172385698678f8c9fb23f76ae028a446bd4c14b5.tar.gz
SERVER-61485 Wrong SBE plan reported by explain() for rejected plans
-rw-r--r--jstests/core/sbe/sbe_explain_rejected_plans.js66
-rw-r--r--src/mongo/db/query/plan_explainer_sbe.h6
2 files changed, 69 insertions, 3 deletions
diff --git a/jstests/core/sbe/sbe_explain_rejected_plans.js b/jstests/core/sbe/sbe_explain_rejected_plans.js
new file mode 100644
index 00000000000..acf2101a4f2
--- /dev/null
+++ b/jstests/core/sbe/sbe_explain_rejected_plans.js
@@ -0,0 +1,66 @@
+/**
+ * Tests that SBE reports correct rejected plans when calling explain().
+ * @tags: [assumes_unsharded_collection]
+ */
+(function() {
+"use strict";
+
+load("jstests/libs/analyze_plan.js");
+load("jstests/libs/collection_drop_recreate.js");
+load("jstests/libs/sbe_util.js");
+
+const isSBEEnabled = checkSBEEnabled(db);
+if (!isSBEEnabled) {
+ jsTestLog("Skipping test because the SBE feature flag is disabled");
+ return;
+}
+
+const coll = assertDropAndRecreateCollection(db, "sbe_explain_rejected_plans");
+assert.commandWorked(coll.createIndex({a: 1}));
+assert.commandWorked(coll.createIndex({b: 1}));
+assert.commandWorked(coll.createIndex({a: 1, b: 1}));
+
+// Insert data, such that index 'a_1_b_1' is preferred.
+for (let a = 0; a < 10; a++) {
+ for (let b = 0; b < 10; b++) {
+ assert.commandWorked(coll.insert({a: a, b: b}));
+ }
+}
+
+const a1b1IndexName = "a_1_b_1";
+const a1IndexName = "a_1";
+const b1IndexName = "b_1";
+const explain = coll.find({a: 7, b: 9}).explain("executionStats");
+
+// Verify that the winner plan has index scan stage on 'a_1_b_1'.
+let ixscans = getPlanStages(getWinningPlan(explain.queryPlanner), "IXSCAN");
+assert.neq(ixscans.length, 0, explain);
+for (let ixscan of ixscans) {
+ assert.eq(ixscan.indexName, a1b1IndexName, explain);
+}
+
+// Verify that the winning SBE plan has index scan stage on 'a_1_b_1'.
+const executionStages = getExecutionStages(explain);
+assert.neq(executionStages.length, 0, explain);
+for (let executionStage of executionStages) {
+ ixscans = getPlanStages(executionStage, "ixseek");
+ assert.neq(ixscans.length, 0);
+ for (let ixscan of ixscans) {
+ assert.eq(ixscan.indexName, a1b1IndexName, ixscan);
+ }
+}
+
+// Verify that rejected plans should have index scan on 'a_1' or 'b_1'.
+for (let rejectedPlan of getRejectedPlans(explain)) {
+ ixscans = getPlanStages(getRejectedPlan(rejectedPlan), "IXSCAN");
+ assert.neq(ixscans.length, 0, explain);
+ for (let ixscan of ixscans) {
+ assert.contains(ixscan.indexName, [a1IndexName, b1IndexName], ixscan);
+ }
+
+ assert(!rejectedPlan.slotBasedPlan.stages.includes("@\"a_1_b_1\""), explain);
+ assert(rejectedPlan.slotBasedPlan.stages.includes("@\"a_1\"") ||
+ rejectedPlan.slotBasedPlan.stages.includes("@\"b_1\""),
+ explain);
+}
+})();
diff --git a/src/mongo/db/query/plan_explainer_sbe.h b/src/mongo/db/query/plan_explainer_sbe.h
index 7ce73608596..5dc97f90641 100644
--- a/src/mongo/db/query/plan_explainer_sbe.h
+++ b/src/mongo/db/query/plan_explainer_sbe.h
@@ -77,11 +77,11 @@ public:
ExplainOptions::Verbosity) const final;
private:
- boost::optional<BSONObj> buildExecPlanDebugInfo(
- const sbe::PlanStage* root, const stage_builder::PlanStageData* data) const {
+ static boost::optional<BSONObj> buildExecPlanDebugInfo(
+ const sbe::PlanStage* root, const stage_builder::PlanStageData* data) {
if (root && data) {
return BSON("slots" << data->debugString() << "stages"
- << sbe::DebugPrinter().print(*_root));
+ << sbe::DebugPrinter().print(*root));
}
return boost::none;
}