Unverified Commit 0c9669a2 authored by Andres Taylor's avatar Andres Taylor Committed by GitHub
Browse files

Merge pull request #11555 from henriknyman/3.2-fix-minimum-cardinality

Fix issue with cost planning index seeks
parents c1ddd24b eaca9d72
Showing with 98 additions and 67 deletions
+98 -67
......@@ -66,7 +66,7 @@ object CommunityContextCreator extends ContextCreator[CompilerContext] {
val metrics: Metrics = if (planContext == null)
null
else
metricsFactory.newMetrics(planContext.statistics)
metricsFactory.newMetrics(planContext.statistics, config)
new CompilerContext(exceptionCreator, tracer, notificationLogger, planContext, typeConverter, createFingerprintReference,
monitors, metrics, queryGraphSolver, config, updateStrategy, debugOptions, clock)
......
......@@ -153,7 +153,8 @@ case class CypherCompilerConfiguration(queryCacheSize: Int,
errorIfShortestPathFallbackUsedAtRuntime: Boolean,
errorIfShortestPathHasCommonNodesAtRuntime: Boolean,
legacyCsvQuoteEscaping: Boolean,
nonIndexedLabelWarningThreshold: Long)
nonIndexedLabelWarningThreshold: Long,
planWithMinimumCardinalityEstimates: Boolean)
trait CypherCacheFlushingMonitor[T] {
......
......@@ -19,15 +19,17 @@
*/
package org.neo4j.cypher.internal.compiler.v3_2.planner.logical
import org.neo4j.cypher.internal.compiler.v3_2.CypherCompilerConfiguration
import org.neo4j.cypher.internal.compiler.v3_2.helpers.CachedFunction
import org.neo4j.cypher.internal.compiler.v3_2.planner.logical.Metrics.{QueryGraphCardinalityModel, CardinalityModel}
import org.neo4j.cypher.internal.compiler.v3_2.planner.logical.Metrics.{CardinalityModel, QueryGraphCardinalityModel}
import org.neo4j.cypher.internal.compiler.v3_2.spi.GraphStatistics
case class CachedMetricsFactory(metricsFactory: MetricsFactory) extends MetricsFactory {
def newCardinalityEstimator(queryGraphCardinalityModel: QueryGraphCardinalityModel): CardinalityModel =
CachedFunction(metricsFactory.newCardinalityEstimator(queryGraphCardinalityModel))
def newCostModel() = CachedFunction(metricsFactory.newCostModel())
def newCostModel(config: CypherCompilerConfiguration) =
CachedFunction(metricsFactory.newCostModel(config: CypherCompilerConfiguration))
def newQueryGraphCardinalityModel(statistics: GraphStatistics) =
CachedFunction(metricsFactory.newQueryGraphCardinalityModel(statistics))
......
......@@ -19,12 +19,13 @@
*/
package org.neo4j.cypher.internal.compiler.v3_2.planner.logical
import org.neo4j.cypher.internal.compiler.v3_2.CypherCompilerConfiguration
import org.neo4j.cypher.internal.compiler.v3_2.planner.logical.Metrics._
import org.neo4j.cypher.internal.compiler.v3_2.planner.logical.plans._
import org.neo4j.cypher.internal.frontend.v3_2.ast.{HasLabels, Property}
import org.neo4j.cypher.internal.ir.v3_2._
object CardinalityCostModel extends CostModel {
case class CardinalityCostModel(config: CypherCompilerConfiguration) extends CostModel {
def VERBOSE = java.lang.Boolean.getBoolean("CardinalityCostModel.VERBOSE")
private val DEFAULT_COST_PER_ROW: CostPerRow = 0.1
......@@ -92,9 +93,7 @@ object CardinalityCostModel extends CostModel {
case _: FindShortestPaths |
_: LegacyNodeIndexSeek |
_: LegacyRelationshipIndexSeek |
_: DirectedRelationshipByIdSeek |
_: UndirectedRelationshipByIdSeek
_: LegacyRelationshipIndexSeek
=> 12.0
case _ // Default
......@@ -106,6 +105,17 @@ object CardinalityCostModel extends CostModel {
case _ => plan.lhs.map(p => p.solved.estimatedCardinality).getOrElse(plan.solved.estimatedCardinality)
}
private def minimumCardinalityEstimateForPlan(plan: LogicalPlan): Cardinality = plan match {
case _: AllNodesScan | _: NodeByLabelScan | _: NodeIndexScan =>
Cardinality(10)
case _: NodeIndexContainsScan | _: NodeIndexEndsWithScan =>
Cardinality(5)
case _ =>
Cardinality.SINGLE
}
private val planWithMinimumCardinalityEstimates: Boolean = config.planWithMinimumCardinalityEstimates
def apply(plan: LogicalPlan, input: QueryGraphSolverInput): Cost = {
val cost = plan match {
case CartesianProduct(lhs, rhs) =>
......@@ -133,8 +143,13 @@ object CardinalityCostModel extends CostModel {
val lhsCost = plan.lhs.map(p => apply(p, input)).getOrElse(Cost(0))
val rhsCost = plan.rhs.map(p => apply(p, input)).getOrElse(Cost(0))
val planCardinality = cardinalityForPlan(plan)
val effectivePlanCardinality =
if (planWithMinimumCardinalityEstimates)
Cardinality.max(planCardinality, minimumCardinalityEstimateForPlan(plan))
else
planCardinality
val rowCost = costPerRow(plan)
val costForThisPlan = planCardinality * rowCost
val costForThisPlan = effectivePlanCardinality * rowCost
val totalCost = costForThisPlan + lhsCost + rhsCost
totalCost
}
......
......@@ -19,6 +19,7 @@
*/
package org.neo4j.cypher.internal.compiler.v3_2.planner.logical
import org.neo4j.cypher.internal.compiler.v3_2.CypherCompilerConfiguration
import org.neo4j.cypher.internal.frontend.v3_2.ast.LabelName
import org.neo4j.cypher.internal.compiler.v3_2.helpers.MapSupport._
import org.neo4j.cypher.internal.compiler.v3_2.planner.logical.Metrics.{CardinalityModel, CostModel, QueryGraphCardinalityModel}
......@@ -65,13 +66,13 @@ case class Metrics(cost: CostModel,
trait MetricsFactory {
def newCardinalityEstimator(queryGraphCardinalityModel: QueryGraphCardinalityModel): CardinalityModel
def newCostModel(): CostModel
def newCostModel(config: CypherCompilerConfiguration): CostModel
def newQueryGraphCardinalityModel(statistics: GraphStatistics): QueryGraphCardinalityModel
def newMetrics(statistics: GraphStatistics) = {
def newMetrics(statistics: GraphStatistics, config: CypherCompilerConfiguration) = {
val queryGraphCardinalityModel = newQueryGraphCardinalityModel(statistics)
val cardinality = newCardinalityEstimator(queryGraphCardinalityModel)
Metrics(newCostModel(), cardinality, queryGraphCardinalityModel)
Metrics(newCostModel(config), cardinality, queryGraphCardinalityModel)
}
}
......
......@@ -19,12 +19,13 @@
*/
package org.neo4j.cypher.internal.compiler.v3_2.planner.logical
import org.neo4j.cypher.internal.compiler.v3_2.CypherCompilerConfiguration
import org.neo4j.cypher.internal.compiler.v3_2.planner.logical.Metrics._
import org.neo4j.cypher.internal.compiler.v3_2.planner.logical.cardinality.QueryGraphCardinalityModel
import org.neo4j.cypher.internal.compiler.v3_2.spi.GraphStatistics
object SimpleMetricsFactory extends MetricsFactory {
def newCostModel(): CostModel = CardinalityCostModel
def newCostModel(config: CypherCompilerConfiguration): CostModel = CardinalityCostModel(config)
def newCardinalityEstimator(queryGraphCardinalityModel: QueryGraphCardinalityModel): CardinalityModel =
new StatisticsBackedCardinalityModel(queryGraphCardinalityModel)
......
......@@ -21,6 +21,7 @@ package org.neo4j.cypher.internal.compiler.v3_2.planner
import java.util
import org.neo4j.cypher.internal.compiler.v3_2.CypherCompilerConfiguration
import org.neo4j.cypher.internal.compiler.v3_2.spi.{GraphStatistics, StatisticsCompletingGraphStatistics}
import org.neo4j.cypher.internal.frontend.v3_2.{LabelId, PropertyKeyId, RelTypeId, SemanticTable}
import org.neo4j.helpers.collection.Pair
......@@ -30,7 +31,7 @@ import org.neo4j.kernel.impl.util.dbstructure.{DbStructureCollector, DbStructure
import scala.collection.JavaConverters._
import scala.collection.{JavaConverters, mutable}
object DbStructureLogicalPlanningConfiguration {
case class DbStructureLogicalPlanningConfiguration(cypherCompilerConfig: CypherCompilerConfiguration) {
def apply(visitable: Visitable[DbStructureVisitor]): LogicalPlanningConfiguration = {
val collector = new DbStructureCollector
......@@ -44,7 +45,7 @@ object DbStructureLogicalPlanningConfiguration {
val resolvedPropertyKeys = resolveTokens(lookup.properties())(PropertyKeyId)
val resolvedRelTypeNames = resolveTokens(lookup.relationshipTypes())(RelTypeId)
new RealLogicalPlanningConfiguration {
new RealLogicalPlanningConfiguration(cypherCompilerConfig) {
override def updateSemanticTableWithTokens(table: SemanticTable) = {
resolvedPropertyKeys.foreach { case (keyName, keyId) => table.resolvedPropertyKeyNames.put(keyName, PropertyKeyId(keyId)) }
......
......@@ -66,8 +66,8 @@ trait LogicalPlanningTestSupport extends CypherTestSupport with AstConstructionT
class SpyableMetricsFactory extends MetricsFactory {
def newCardinalityEstimator(queryGraphCardinalityModel: QueryGraphCardinalityModel) =
SimpleMetricsFactory.newCardinalityEstimator(queryGraphCardinalityModel)
def newCostModel() =
SimpleMetricsFactory.newCostModel()
def newCostModel(config: CypherCompilerConfiguration) =
SimpleMetricsFactory.newCostModel(config)
def newQueryGraphCardinalityModel(statistics: GraphStatistics): QueryGraphCardinalityModel =
SimpleMetricsFactory.newQueryGraphCardinalityModel(statistics)
}
......@@ -92,7 +92,7 @@ trait LogicalPlanningTestSupport extends CypherTestSupport with AstConstructionT
def newMetricsFactory = SimpleMetricsFactory
def newSimpleMetrics(stats: GraphStatistics = newMockedGraphStatistics) = newMetricsFactory.newMetrics(stats)
def newSimpleMetrics(stats: GraphStatistics = newMockedGraphStatistics) = newMetricsFactory.newMetrics(stats, config)
def newMockedGraphStatistics = mock[GraphStatistics]
......@@ -172,7 +172,8 @@ trait LogicalPlanningTestSupport extends CypherTestSupport with AstConstructionT
errorIfShortestPathFallbackUsedAtRuntime = false,
errorIfShortestPathHasCommonNodesAtRuntime = true,
legacyCsvQuoteEscaping = false,
nonIndexedLabelWarningThreshold = 10000
nonIndexedLabelWarningThreshold = 10000,
planWithMinimumCardinalityEstimates = false
)
def buildPlannerQuery(query: String, lookup: Option[QualifiedName => ProcedureSignature] = None) = {
......
......@@ -61,7 +61,6 @@ trait LogicalPlanningTestSupport2 extends CypherTestSupport with AstConstruction
planSingleQuery(query)
}
var queryGraphSolver: QueryGraphSolver = new IDPQueryGraphSolver(SingleComponentPlanner(mock[IDPQueryGraphSolverMonitor]), cartesianProductsOrValueJoins, mock[IDPQueryGraphSolverMonitor])
val realConfig = new RealLogicalPlanningConfiguration
val cypherCompilerConfig = CypherCompilerConfiguration(
queryCacheSize = 100,
statsDivergenceCalculator = PlanFingerprint.divergenceNoDecayCalculator(0.5, 1000),
......@@ -71,15 +70,17 @@ trait LogicalPlanningTestSupport2 extends CypherTestSupport with AstConstruction
errorIfShortestPathFallbackUsedAtRuntime = false,
errorIfShortestPathHasCommonNodesAtRuntime = true,
legacyCsvQuoteEscaping = false,
nonIndexedLabelWarningThreshold = 10000
nonIndexedLabelWarningThreshold = 10000,
planWithMinimumCardinalityEstimates = false
)
val realConfig = new RealLogicalPlanningConfiguration(cypherCompilerConfig)
def solvedWithEstimation(cardinality: Cardinality) = CardinalityEstimation.lift(PlannerQuery.empty, cardinality)
implicit class LogicalPlanningEnvironment[C <: LogicalPlanningConfiguration](config: C) {
lazy val semanticTable = config.updateSemanticTableWithTokens(SemanticTable())
def metricsFactory = new MetricsFactory {
def newCostModel() =
def newCostModel(ignore: CypherCompilerConfiguration) =
(plan: LogicalPlan, input: QueryGraphSolverInput) => config.costModel()(plan -> input)
def newCardinalityEstimator(queryGraphCardinalityModel: QueryGraphCardinalityModel) =
......@@ -168,7 +169,7 @@ trait LogicalPlanningTestSupport2 extends CypherTestSupport with AstConstruction
def getLogicalPlanFor(queryString: String): (Option[PeriodicCommit], LogicalPlan, SemanticTable) = {
val mkException = new SyntaxExceptionCreator(queryString, Some(pos))
val metrics = metricsFactory.newMetrics(planContext.statistics)
val metrics = metricsFactory.newMetrics(planContext.statistics, cypherCompilerConfig)
def context = ContextHelper.create(planContext = planContext, exceptionCreator = mkException, queryGraphSolver = queryGraphSolver, metrics = metrics, config = cypherCompilerConfig)
val state = CompilationState(queryString, None, IDPPlannerName)
......@@ -178,10 +179,10 @@ trait LogicalPlanningTestSupport2 extends CypherTestSupport with AstConstruction
}
def estimate(qg: QueryGraph, input: QueryGraphSolverInput = QueryGraphSolverInput.empty) =
metricsFactory.newMetrics(config.graphStatistics).queryGraphCardinalityModel(qg, input, semanticTable)
metricsFactory.newMetrics(config.graphStatistics, cypherCompilerConfig).queryGraphCardinalityModel(qg, input, semanticTable)
def withLogicalPlanningContext[T](f: (C, LogicalPlanningContext) => T): T = {
val metrics = metricsFactory.newMetrics(config.graphStatistics)
val metrics = metricsFactory.newMetrics(config.graphStatistics, cypherCompilerConfig)
val logicalPlanProducer = LogicalPlanProducer(metrics.cardinality)
val ctx = LogicalPlanningContext(
planContext = planContext,
......@@ -204,7 +205,7 @@ trait LogicalPlanningTestSupport2 extends CypherTestSupport with AstConstruction
class given extends StubbedLogicalPlanningConfiguration(realConfig)
class fromDbStructure(dbStructure: Visitable[DbStructureVisitor])
extends DelegatingLogicalPlanningConfiguration(DbStructureLogicalPlanningConfiguration(dbStructure))
extends DelegatingLogicalPlanningConfiguration(DbStructureLogicalPlanningConfiguration(cypherCompilerConfig)(dbStructure))
implicit def propertyKeyId(label: String)(implicit semanticTable: SemanticTable): PropertyKeyId =
semanticTable.resolvedPropertyKeyNames(label)
......
......@@ -19,7 +19,7 @@
*/
package org.neo4j.cypher.internal.compiler.v3_2.planner
import org.neo4j.cypher.internal.compiler.v3_2.HardcodedGraphStatistics
import org.neo4j.cypher.internal.compiler.v3_2.{CypherCompilerConfiguration, HardcodedGraphStatistics}
import org.neo4j.cypher.internal.compiler.v3_2.planner.logical.Metrics.{CardinalityModel, QueryGraphCardinalityModel, QueryGraphSolverInput}
import org.neo4j.cypher.internal.compiler.v3_2.planner.logical.plans.LogicalPlan
import org.neo4j.cypher.internal.compiler.v3_2.planner.logical.{CardinalityCostModel, Metrics, StatisticsBackedCardinalityModel}
......@@ -27,7 +27,7 @@ import org.neo4j.cypher.internal.compiler.v3_2.spi.GraphStatistics
import org.neo4j.cypher.internal.frontend.v3_2.SemanticTable
import org.neo4j.cypher.internal.ir.v3_2.{Cardinality, Cost, PlannerQuery, QueryGraph}
case class RealLogicalPlanningConfiguration()
case class RealLogicalPlanningConfiguration(cypherCompilerConfig: CypherCompilerConfiguration)
extends LogicalPlanningConfiguration with LogicalPlanningConfigurationAdHocSemanticTable {
override def cardinalityModel(queryGraphCardinalityModel: QueryGraphCardinalityModel): CardinalityModel = {
......@@ -38,7 +38,7 @@ case class RealLogicalPlanningConfiguration()
}
override def costModel(): PartialFunction[(LogicalPlan, QueryGraphSolverInput), Cost] = {
val model: Metrics.CostModel = CardinalityCostModel
val model: Metrics.CostModel = CardinalityCostModel(cypherCompilerConfig)
({
case (plan: LogicalPlan, input: QueryGraphSolverInput) => model(plan, input)
})
......
......@@ -40,7 +40,7 @@ class CardinalityCostModelTest extends CypherFunSuite with LogicalPlanningTestSu
)(solvedWithEstimation(10.0)), "a", SemanticDirection.OUTGOING, Seq.empty, "b", "r1")(solvedWithEstimation(100.0))
)(solvedWithEstimation(10.0))
CardinalityCostModel(plan, QueryGraphSolverInput.empty) should equal(Cost(231))
CardinalityCostModel(config)(plan, QueryGraphSolverInput.empty) should equal(Cost(231))
}
test("should introduce increase cost when estimating an eager operator and lazyness is preferred") {
......@@ -54,7 +54,7 @@ class CardinalityCostModelTest extends CypherFunSuite with LogicalPlanningTestSu
val pleaseLazy = QueryGraphSolverInput.empty.withPreferredStrictness(LazyMode)
val whatever = QueryGraphSolverInput.empty
CardinalityCostModel(plan, whatever) should be < CardinalityCostModel(plan, pleaseLazy)
CardinalityCostModel(config)(plan, whatever) should be < CardinalityCostModel(config)(plan, pleaseLazy)
}
test("non-lazy plan should be penalized when estimating cost wrt a lazy one when lazyness is preferred") {
......@@ -87,10 +87,10 @@ class CardinalityCostModelTest extends CypherFunSuite with LogicalPlanningTestSu
)(solvedWithEstimation(250.0))
val whatever = QueryGraphSolverInput.empty
CardinalityCostModel(lazyPlan, whatever) should be > CardinalityCostModel(eagerPlan, whatever)
CardinalityCostModel(config)(lazyPlan, whatever) should be > CardinalityCostModel(config)(eagerPlan, whatever)
val pleaseLazy = QueryGraphSolverInput.empty.withPreferredStrictness(LazyMode)
CardinalityCostModel(lazyPlan, pleaseLazy) should be < CardinalityCostModel(eagerPlan, pleaseLazy)
CardinalityCostModel(config)(lazyPlan, pleaseLazy) should be < CardinalityCostModel(config)(eagerPlan, pleaseLazy)
}
test("multiple property expressions are counted for in cost") {
......@@ -103,7 +103,7 @@ class CardinalityCostModelTest extends CypherFunSuite with LogicalPlanningTestSu
val numberOfPredicates = 3
val costForSelection = cardinality * numberOfPredicates
val costForArgument = cardinality * .1
CardinalityCostModel(plan, QueryGraphSolverInput.empty) should equal(Cost(costForSelection + costForArgument))
CardinalityCostModel(config)(plan, QueryGraphSolverInput.empty) should equal(Cost(costForSelection + costForArgument))
}
}
......@@ -100,7 +100,7 @@ class PickBestPlanUsingHintsAndCostTest extends CypherFunSuite with LogicalPlann
private def assertTopPlan(winner: LogicalPlan, candidates: LogicalPlan*)(GIVEN: given) {
val environment = LogicalPlanningEnvironment(GIVEN)
val metrics: Metrics = environment.metricsFactory.newMetrics(GIVEN.graphStatistics)
val metrics: Metrics = environment.metricsFactory.newMetrics(GIVEN.graphStatistics, cypherCompilerConfig)
implicit val context = LogicalPlanningContext(null, LogicalPlanProducer(metrics.cardinality), metrics, null, null, notificationLogger = devNullLogger)
pickBestPlanUsingHintsAndCost(context)(candidates) should equal(Some(winner))
pickBestPlanUsingHintsAndCost(context)(candidates.reverse) should equal(Some(winner))
......
......@@ -36,7 +36,7 @@ class AllNodesLeafPlannerTest extends CypherFunSuite with LogicalPlanningTestSup
implicit val planContext = newMockedPlanContext
implicit val context = newMockedLogicalPlanningContext(
planContext = planContext,
metrics = newMockedMetricsFactory.newMetrics(hardcodedStatistics))
metrics = newMockedMetricsFactory.newMetrics(hardcodedStatistics, config))
// when
val resultPlans = allNodesLeafPlanner(queryGraph)
......
......@@ -52,13 +52,13 @@ class IdSeekLeafPlannerTest extends CypherFunSuite with LogicalPlanningTestSupp
)
val factory = newMockedMetricsFactory
when(factory.newCostModel()).thenReturn((plan: LogicalPlan, input: QueryGraphSolverInput) => plan match {
when(factory.newCostModel(config)).thenReturn((plan: LogicalPlan, input: QueryGraphSolverInput) => plan match {
case _: NodeByIdSeek => Cost(1)
case _ => Cost(Double.MaxValue)
})
implicit val context = newMockedLogicalPlanningContext(
planContext = newMockedPlanContext,
metrics = factory.newMetrics(statistics)
metrics = factory.newMetrics(statistics, config)
)
when(context.semanticTable.isNode(variable)).thenReturn(true)
......@@ -87,13 +87,13 @@ class IdSeekLeafPlannerTest extends CypherFunSuite with LogicalPlanningTestSupp
)
val factory = newMockedMetricsFactory
when(factory.newCostModel()).thenReturn((plan: LogicalPlan, input: QueryGraphSolverInput) => plan match {
when(factory.newCostModel(config)).thenReturn((plan: LogicalPlan, input: QueryGraphSolverInput) => plan match {
case _: NodeByIdSeek => Cost(1)
case _ => Cost(Double.MaxValue)
})
implicit val context = newMockedLogicalPlanningContext(
planContext = newMockedPlanContext,
metrics = factory.newMetrics(statistics)
metrics = factory.newMetrics(statistics, config)
)
when(context.semanticTable.isNode(variable)).thenReturn(true)
......@@ -120,13 +120,13 @@ class IdSeekLeafPlannerTest extends CypherFunSuite with LogicalPlanningTestSupp
)
val factory = newMockedMetricsFactory
when(factory.newCostModel()).thenReturn((plan: LogicalPlan, input: QueryGraphSolverInput) => plan match {
when(factory.newCostModel(config)).thenReturn((plan: LogicalPlan, input: QueryGraphSolverInput) => plan match {
case _: NodeByIdSeek => Cost(1)
case _ => Cost(Double.MaxValue)
})
implicit val context = newMockedLogicalPlanningContext(
planContext = newMockedPlanContext,
metrics = factory.newMetrics(statistics)
metrics = factory.newMetrics(statistics, config)
)
when(context.semanticTable.isNode(variable)).thenReturn(true)
......@@ -151,13 +151,13 @@ class IdSeekLeafPlannerTest extends CypherFunSuite with LogicalPlanningTestSupp
)
val factory = newMockedMetricsFactory
when(factory.newCostModel()).thenReturn((plan: LogicalPlan, input: QueryGraphSolverInput) => plan match {
when(factory.newCostModel(config)).thenReturn((plan: LogicalPlan, input: QueryGraphSolverInput) => plan match {
case _: NodeByIdSeek => Cost(1)
case _ => Cost(Double.MaxValue)
})
implicit val context = newMockedLogicalPlanningContext(
planContext = newMockedPlanContext,
metrics = factory.newMetrics(statistics)
metrics = factory.newMetrics(statistics, config)
)
when(context.semanticTable.isNode(variable)).thenReturn(true)
......@@ -187,13 +187,13 @@ class IdSeekLeafPlannerTest extends CypherFunSuite with LogicalPlanningTestSupp
)
val factory = newMockedMetricsFactory
when(factory.newCostModel()).thenReturn((plan: LogicalPlan, input: QueryGraphSolverInput) => plan match {
when(factory.newCostModel(config)).thenReturn((plan: LogicalPlan, input: QueryGraphSolverInput) => plan match {
case _: DirectedRelationshipByIdSeek => Cost(1)
case _ => Cost(Double.MaxValue)
})
implicit val context = newMockedLogicalPlanningContext(
planContext = newMockedPlanContext,
metrics = factory.newMetrics(statistics)
metrics = factory.newMetrics(statistics, config)
)
when(context.semanticTable.isRelationship(rIdent)).thenReturn(true)
......@@ -224,13 +224,13 @@ class IdSeekLeafPlannerTest extends CypherFunSuite with LogicalPlanningTestSupp
patternRelationships = Set(patternRel))
val factory = newMockedMetricsFactory
when(factory.newCostModel()).thenReturn((plan: LogicalPlan, input: QueryGraphSolverInput) => plan match {
when(factory.newCostModel(config)).thenReturn((plan: LogicalPlan, input: QueryGraphSolverInput) => plan match {
case _: UndirectedRelationshipByIdSeek => Cost(2)
case _ => Cost(Double.MaxValue)
})
implicit val context = newMockedLogicalPlanningContext(
planContext = newMockedPlanContext,
metrics = factory.newMetrics(statistics)
metrics = factory.newMetrics(statistics, config)
)
when(context.semanticTable.isRelationship(rIdent)).thenReturn(true)
......@@ -267,13 +267,13 @@ class IdSeekLeafPlannerTest extends CypherFunSuite with LogicalPlanningTestSupp
patternRelationships = Set(patternRel))
val factory = newMockedMetricsFactory
when(factory.newCostModel()).thenReturn((plan: LogicalPlan, input: QueryGraphSolverInput) => plan match {
when(factory.newCostModel(config)).thenReturn((plan: LogicalPlan, input: QueryGraphSolverInput) => plan match {
case _: UndirectedRelationshipByIdSeek => Cost(2)
case _ => Cost(Double.MaxValue)
})
implicit val context = newMockedLogicalPlanningContext(
planContext = newMockedPlanContext,
metrics = factory.newMetrics(statistics)
metrics = factory.newMetrics(statistics, config)
)
when(context.semanticTable.isRelationship(rIdent)).thenReturn(true)
......@@ -314,13 +314,13 @@ class IdSeekLeafPlannerTest extends CypherFunSuite with LogicalPlanningTestSupp
patternRelationships = Set(patternRel))
val factory = newMockedMetricsFactory
when(factory.newCostModel()).thenReturn((plan: LogicalPlan, input: QueryGraphSolverInput) => plan match {
when(factory.newCostModel(config)).thenReturn((plan: LogicalPlan, input: QueryGraphSolverInput) => plan match {
case _: UndirectedRelationshipByIdSeek => Cost(2)
case _ => Cost(Double.MaxValue)
})
implicit val context = newMockedLogicalPlanningContext(
planContext = newMockedPlanContext,
metrics = factory.newMetrics(statistics)
metrics = factory.newMetrics(statistics, config)
)
when(context.semanticTable.isRelationship(rIdent)).thenReturn(true)
......
......@@ -46,7 +46,7 @@ class LabelScanLeafPlannerTest extends CypherFunSuite with LogicalPlanningTestSu
patternNodes = Set(idName))
val factory = newMockedMetricsFactory
when(factory.newCostModel()).thenReturn((plan: LogicalPlan, input: QueryGraphSolverInput) => plan match {
when(factory.newCostModel(config)).thenReturn((plan: LogicalPlan, input: QueryGraphSolverInput) => plan match {
case _: NodeByLabelScan => Cost(1)
case _ => Cost(Double.MaxValue)
})
......@@ -57,7 +57,7 @@ class LabelScanLeafPlannerTest extends CypherFunSuite with LogicalPlanningTestSu
implicit val context = newMockedLogicalPlanningContext(
semanticTable = semanticTable,
planContext = newMockedPlanContext,
metrics = factory.newMetrics(statistics)
metrics = factory.newMetrics(statistics, config)
)
// when
......@@ -79,7 +79,7 @@ class LabelScanLeafPlannerTest extends CypherFunSuite with LogicalPlanningTestSu
patternNodes = Set(idName))
val factory = newMockedMetricsFactory
when(factory.newCostModel()).thenReturn((plan: LogicalPlan, input: QueryGraphSolverInput) => plan match {
when(factory.newCostModel(config)).thenReturn((plan: LogicalPlan, input: QueryGraphSolverInput) => plan match {
case _: NodeByLabelScan => Cost(100)
case _ => Cost(Double.MaxValue)
})
......@@ -90,7 +90,7 @@ class LabelScanLeafPlannerTest extends CypherFunSuite with LogicalPlanningTestSu
implicit val context = newMockedLogicalPlanningContext(
semanticTable = semanticTable,
planContext = newMockedPlanContext,
metrics = factory.newMetrics(statistics)
metrics = factory.newMetrics(statistics, config)
)
// when
......
......@@ -41,13 +41,13 @@ class LegacyHintLeafPlannerTest extends CypherFunSuite with LogicalPlanningTest
)
val factory = newMockedMetricsFactory
when(factory.newCostModel()).thenReturn((plan: LogicalPlan, input: QueryGraphSolverInput) => plan match {
when(factory.newCostModel(config)).thenReturn((plan: LogicalPlan, input: QueryGraphSolverInput) => plan match {
case _: LegacyNodeIndexSeek => Cost(1)
case _ => Cost(Double.MaxValue)
})
implicit val context = newMockedLogicalPlanningContext(
planContext = newMockedPlanContext,
metrics = factory.newMetrics(statistics)
metrics = factory.newMetrics(statistics, config)
)
when(context.semanticTable.isNode(variable)).thenReturn(true)
......@@ -67,13 +67,13 @@ class LegacyHintLeafPlannerTest extends CypherFunSuite with LogicalPlanningTest
)
val factory = newMockedMetricsFactory
when(factory.newCostModel()).thenReturn((plan: LogicalPlan, input: QueryGraphSolverInput) => plan match {
when(factory.newCostModel(config)).thenReturn((plan: LogicalPlan, input: QueryGraphSolverInput) => plan match {
case _: LegacyNodeIndexSeek => Cost(1)
case _ => Cost(Double.MaxValue)
})
implicit val context = newMockedLogicalPlanningContext(
planContext = newMockedPlanContext,
metrics = factory.newMetrics(statistics)
metrics = factory.newMetrics(statistics, config)
)
when(context.semanticTable.isNode(variable)).thenReturn(true)
......
......@@ -52,7 +52,7 @@ class OuterHashJoinTest extends CypherFunSuite with LogicalPlanningTestSupport {
)
val factory = newMockedMetricsFactory
when(factory.newCostModel()).thenReturn((plan: LogicalPlan, input: QueryGraphSolverInput) => plan match {
when(factory.newCostModel(config)).thenReturn((plan: LogicalPlan, input: QueryGraphSolverInput) => plan match {
case AllNodesScan(IdName("b"), _) => Cost(1) // Make sure we start the inner plan using b
case _ => Cost(1000)
})
......@@ -62,7 +62,7 @@ class OuterHashJoinTest extends CypherFunSuite with LogicalPlanningTestSupport {
implicit val context = newMockedLogicalPlanningContext(
planContext = newMockedPlanContext,
strategy = newMockedStrategy(innerPlan),
metrics = factory.newMetrics(hardcodedStatistics)
metrics = factory.newMetrics(hardcodedStatistics, config)
)
val left = newMockedLogicalPlanWithPatterns(Set(aNode))
val plans = outerHashJoin(optionalQg, left)
......@@ -81,7 +81,7 @@ class OuterHashJoinTest extends CypherFunSuite with LogicalPlanningTestSupport {
)
val factory = newMockedMetricsFactory
when(factory.newCostModel()).thenReturn((plan: LogicalPlan, input: QueryGraphSolverInput) => plan match {
when(factory.newCostModel(config)).thenReturn((plan: LogicalPlan, input: QueryGraphSolverInput) => plan match {
case AllNodesScan(IdName("b"), _) => Cost(1) // Make sure we start the inner plan using b
case _ => Cost(1000)
})
......@@ -91,7 +91,7 @@ class OuterHashJoinTest extends CypherFunSuite with LogicalPlanningTestSupport {
implicit val context = newMockedLogicalPlanningContext(
planContext = newMockedPlanContext,
strategy = newMockedStrategy(innerPlan),
metrics = factory.newMetrics(hardcodedStatistics)
metrics = factory.newMetrics(hardcodedStatistics, config)
)
val left = newMockedLogicalPlanWithPatterns(Set(aNode))
val plan = outerHashJoin(optionalQg, left).getOrElse(fail("No result from outerHashJoin"))
......
......@@ -87,6 +87,7 @@ class CompilerEngineDelegator(graph: GraphDatabaseQueryService,
errorIfShortestPathFallbackUsedAtRuntime: Boolean,
errorIfShortestPathHasCommonNodesAtRuntime: Boolean,
legacyCsvQuoteEscaping: Boolean,
planWithMinimumCardinalityEstimates: Boolean,
logProvider: LogProvider,
compatibilityFactory: CompatibilityFactory) {
......@@ -103,7 +104,8 @@ class CompilerEngineDelegator(graph: GraphDatabaseQueryService,
errorIfShortestPathFallbackUsedAtRuntime = errorIfShortestPathFallbackUsedAtRuntime,
errorIfShortestPathHasCommonNodesAtRuntime = errorIfShortestPathHasCommonNodesAtRuntime,
legacyCsvQuoteEscaping = legacyCsvQuoteEscaping,
nonIndexedLabelWarningThreshold = getNonIndexedLabelWarningThreshold
nonIndexedLabelWarningThreshold = getNonIndexedLabelWarningThreshold,
planWithMinimumCardinalityEstimates = planWithMinimumCardinalityEstimates
)
private final val ILLEGAL_PLANNER_RUNTIME_COMBINATIONS: Set[(CypherPlanner, CypherRuntime)] = Set((CypherPlanner.rule, CypherRuntime.compiled))
......
......@@ -232,6 +232,10 @@ class ExecutionEngine(val queryService: GraphDatabaseQueryService,
queryService, GraphDatabaseSettings.csv_legacy_quote_escaping,
GraphDatabaseSettings.csv_legacy_quote_escaping.getDefaultValue.toBoolean
)
val planWithMinimumCardinalityEstimates = optGraphSetting[java.lang.Boolean](
queryService, GraphDatabaseSettings.cypher_plan_with_minimum_cardinality_estimates,
GraphDatabaseSettings.cypher_plan_with_minimum_cardinality_estimates.getDefaultValue.toBoolean
)
if (((version != CypherVersion.v2_3) || (version != CypherVersion.v3_1) || (version != CypherVersion.v3_2)) &&
(planner == CypherPlanner.greedy || planner == CypherPlanner.idp || planner == CypherPlanner.dp)) {
......@@ -244,7 +248,8 @@ class ExecutionEngine(val queryService: GraphDatabaseQueryService,
val compatibilityCache = new CompatibilityCache(compatibilityFactory)
new CompilerEngineDelegator(queryService, kernel, kernelMonitors, version, planner, runtime,
useErrorsOverWarnings, idpMaxTableSize, idpIterationDuration, errorIfShortestPathFallbackUsedAtRuntime,
errorIfShortestPathHasCommonNodesAtRuntime, legacyCsvQuoteEscaping, logProvider, compatibilityCache)
errorIfShortestPathHasCommonNodesAtRuntime, legacyCsvQuoteEscaping, planWithMinimumCardinalityEstimates,
logProvider, compatibilityCache)
}
private def getPlanCacheSize: Int =
......
......@@ -108,7 +108,8 @@ class CartesianProductNotificationAcceptanceTest extends CypherFunSuite with Gra
errorIfShortestPathFallbackUsedAtRuntime = false,
errorIfShortestPathHasCommonNodesAtRuntime = true,
legacyCsvQuoteEscaping = false,
nonIndexedLabelWarningThreshold = 10000L
nonIndexedLabelWarningThreshold = 10000L,
planWithMinimumCardinalityEstimates = false
),
Clock.systemUTC(),
WrappedMonitors(kernelMonitors),
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment