diff --git a/src/engine/QueryExecutionTree.cpp b/src/engine/QueryExecutionTree.cpp index 49ceb340aa..cef01b1129 100644 --- a/src/engine/QueryExecutionTree.cpp +++ b/src/engine/QueryExecutionTree.cpp @@ -77,10 +77,15 @@ QueryExecutionTree::selectedVariablesToColumnIndices( // _____________________________________________________________________________ size_t QueryExecutionTree::getCostEstimate() { - if (cachedResult_) { - // result is pinned in cache. Nothing to compute + // If the result is cached and `zero-cost-estimate-for-cached-subtrees` is set + // to `true`, we set the cost estimate to zero. + if (cachedResult_ && + RuntimeParameters().get<"zero-cost-estimate-for-cached-subtree">()) { return 0; } + + // Otherwise, we return the cost estimate of the root operation. For index + // scans, we assume one unit of work per result row. if (getRootOperation()->isIndexScanWithNumVariables(1)) { return getSizeEstimate(); } else { diff --git a/src/global/RuntimeParameters.h b/src/global/RuntimeParameters.h index f61705e7fc..f05c23b081 100644 --- a/src/global/RuntimeParameters.h +++ b/src/global/RuntimeParameters.h @@ -60,6 +60,9 @@ inline auto& RuntimeParameters() { // its size estimate will be the size of the block divided by this // value. SizeT<"small-index-scan-size-estimate-divisor">{5}, + // Determines whether the cost estimate for a cached subtree should be + // set to zero in query planning. + Bool<"zero-cost-estimate-for-cached-subtree">{false}, }; }(); return params; diff --git a/test/OperationTest.cpp b/test/OperationTest.cpp index 96c6525221..c564707514 100644 --- a/test/OperationTest.cpp +++ b/test/OperationTest.cpp @@ -242,15 +242,28 @@ TEST(OperationTest, estimatesForCachedResults) { [[maybe_unused]] auto res = qet->getResult(); } - // The result is now cached inside the static execution context, if we create - // the same operation again, the cost estimate is 0. The size estimate doesn't + // The result is now cached inside the static execution context. If we create + // the same operation again and `zero-cost-estimate-for-cached-subtrees` is + // set to `true`, the cost estimate should be zero. The size estimate does not // change (see the `getCostEstimate` function for details on why). { + auto restoreWhenScopeEnds = + setRuntimeParameterForTest<"zero-cost-estimate-for-cached-subtree">( + true); auto qet = makeQet(); EXPECT_EQ(qet->getCacheKey(), qet->getRootOperation()->getCacheKey()); EXPECT_EQ(qet->getSizeEstimate(), 24u); EXPECT_EQ(qet->getCostEstimate(), 0u); } + { + auto restoreWhenScopeEnds = + setRuntimeParameterForTest<"zero-cost-estimate-for-cached-subtree">( + false); + auto qet = makeQet(); + EXPECT_EQ(qet->getCacheKey(), qet->getRootOperation()->getCacheKey()); + EXPECT_EQ(qet->getSizeEstimate(), 24u); + EXPECT_EQ(qet->getCostEstimate(), 210u); + } } // ________________________________________________