Generate multiple plans and use the least costly one
Summary: This is a simple integration of multiple plan generation and cost estimation. Each plan produced by VariableStartPlanner is cost estimated and the best is used for execution. Reviewers: florijan, mislav.bradac, buda Reviewed By: florijan Subscribers: pullbot Differential Revision: https://phabricator.memgraph.io/D424
This commit is contained in:
@@ -1,6 +1,7 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <ctime>
|
#include <ctime>
|
||||||
|
#include <limits>
|
||||||
|
|
||||||
#include "database/graph_db_accessor.hpp"
|
#include "database/graph_db_accessor.hpp"
|
||||||
#include "query/context.hpp"
|
#include "query/context.hpp"
|
||||||
@@ -40,13 +41,33 @@ void Interpret(const std::string &query, GraphDbAccessor &db_accessor,
|
|||||||
high_level_tree->Accept(symbol_generator);
|
high_level_tree->Accept(symbol_generator);
|
||||||
|
|
||||||
// high level tree -> logical plan
|
// high level tree -> logical plan
|
||||||
auto logical_plan = plan::MakeLogicalPlan<plan::RuleBasedPlanner>(
|
std::unique_ptr<plan::LogicalOperator> logical_plan;
|
||||||
visitor.storage(), symbol_table, &db_accessor);
|
double query_plan_cost_estimation = 0.0;
|
||||||
|
// TODO: Use gflags
|
||||||
// cost estimation
|
bool FLAGS_query_cost_planner = true;
|
||||||
plan::CostEstimator cost_estimator(db_accessor);
|
if (FLAGS_query_cost_planner) {
|
||||||
logical_plan->Accept(cost_estimator);
|
auto plans = plan::MakeLogicalPlan<plan::VariableStartPlanner>(
|
||||||
double query_plan_cost_estimation = cost_estimator.cost();
|
visitor.storage(), symbol_table, &db_accessor);
|
||||||
|
double min_cost = std::numeric_limits<double>::max();
|
||||||
|
for (auto &plan : plans) {
|
||||||
|
plan::CostEstimator estimator(db_accessor);
|
||||||
|
plan->Accept(estimator);
|
||||||
|
auto cost = estimator.cost();
|
||||||
|
if (!logical_plan || cost < min_cost) {
|
||||||
|
// We won't be iterating over plans anymore, so it's ok to invalidate
|
||||||
|
// unique_ptrs inside.
|
||||||
|
logical_plan = std::move(plan);
|
||||||
|
min_cost = cost;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
query_plan_cost_estimation = min_cost;
|
||||||
|
} else {
|
||||||
|
logical_plan = plan::MakeLogicalPlan<plan::RuleBasedPlanner>(
|
||||||
|
visitor.storage(), symbol_table, &db_accessor);
|
||||||
|
plan::CostEstimator cost_estimator(db_accessor);
|
||||||
|
logical_plan->Accept(cost_estimator);
|
||||||
|
query_plan_cost_estimation = cost_estimator.cost();
|
||||||
|
}
|
||||||
|
|
||||||
// generate frame based on symbol table max_position
|
// generate frame based on symbol table max_position
|
||||||
Frame frame(symbol_table.max_position());
|
Frame frame(symbol_table.max_position());
|
||||||
@@ -84,7 +105,7 @@ void Interpret(const std::string &query, GraphDbAccessor &db_accessor,
|
|||||||
auto cursor = logical_plan->MakeCursor(db_accessor);
|
auto cursor = logical_plan->MakeCursor(db_accessor);
|
||||||
while (cursor->Pull(frame, symbol_table)) continue;
|
while (cursor->Pull(frame, symbol_table)) continue;
|
||||||
} else {
|
} else {
|
||||||
throw QueryRuntimeException("Unknown top level LogicalOp");
|
throw QueryRuntimeException("Unknown top level LogicalOperator");
|
||||||
}
|
}
|
||||||
|
|
||||||
clock_t execution_end_time = clock();
|
clock_t execution_end_time = clock();
|
||||||
@@ -100,11 +121,10 @@ void Interpret(const std::string &query, GraphDbAccessor &db_accessor,
|
|||||||
summary["query_plan_execution_time"] =
|
summary["query_plan_execution_time"] =
|
||||||
time_second(planning_end_time, execution_end_time);
|
time_second(planning_end_time, execution_end_time);
|
||||||
summary["query_cost_estimate"] = query_plan_cost_estimation;
|
summary["query_cost_estimate"] = query_plan_cost_estimation;
|
||||||
//
|
|
||||||
// TODO set summary['type'] based on transaction metadata
|
// TODO set summary['type'] based on transaction metadata
|
||||||
// the type can't be determined based only on top level LogicalOp
|
// the type can't be determined based only on top level LogicalOperator
|
||||||
// (for example MATCH DELETE RETURN will have Produce as it's top)
|
// (for example MATCH DELETE RETURN will have Produce as it's top)
|
||||||
// for now always se "rw" because something must be set, but it doesn't
|
// for now always use "rw" because something must be set, but it doesn't
|
||||||
// have to be correct (for Bolt clients)
|
// have to be correct (for Bolt clients)
|
||||||
summary["type"] = "rw";
|
summary["type"] = "rw";
|
||||||
stream.Summary(summary);
|
stream.Summary(summary);
|
||||||
|
|||||||
Reference in New Issue
Block a user