blob: ee52966b4a26b939cd2b35e4c650eef610cb2afe [file] [log] [blame]
/**
* Copyright 2011-2015 Quickstep Technologies LLC.
* Copyright 2015 Pivotal Software, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
**/
#include "query_optimizer/PhysicalGenerator.hpp"
#include <memory>
#include <unordered_map>
#include <vector>
#include "query_optimizer/Validator.hpp"
#include "query_optimizer/logical/Logical.hpp"
#include "query_optimizer/physical/Physical.hpp"
#include "query_optimizer/rules/PruneColumns.hpp"
#include "query_optimizer/strategy/Aggregate.hpp"
#include "query_optimizer/strategy/Join.hpp"
#include "query_optimizer/strategy/OneToOne.hpp"
#include "query_optimizer/strategy/Selection.hpp"
#include "query_optimizer/strategy/Strategy.hpp"
#include "glog/logging.h"
namespace quickstep {
namespace optimizer {
namespace L = ::quickstep::optimizer::logical;
namespace P = ::quickstep::optimizer::physical;
namespace S = ::quickstep::optimizer::strategy;
void PhysicalGenerator::createStrategies() {
// Note that the ordering matters.
// The strategy that can create better plans should be inserted first.
strategies_.emplace_back(new S::Join(this));
strategies_.emplace_back(new S::Aggregate(this));
strategies_.emplace_back(new S::Selection(this));
strategies_.emplace_back(new S::OneToOne(this));
}
P::PhysicalPtr PhysicalGenerator::generatePlan(
const L::LogicalPtr &logical_plan) {
physical_plan_ = generateInitialPlan(logical_plan);
return optimizePlan();
}
P::PhysicalPtr PhysicalGenerator::generateInitialPlan(
const L::LogicalPtr &logical_plan) {
// Choose the first generated physical plan as the best one.
P::PhysicalPtr physical_plan;
for (std::unique_ptr<S::Strategy> &strategy : strategies_) {
DVLOG(5) << "Apply strategy " << strategy->getName() << " to "
<< logical_plan->getShortString();
if (strategy->generatePlan(logical_plan, &physical_plan)) {
DVLOG(5) << "Result:\n" << physical_plan->toString();
break;
}
}
CHECK(physical_plan != nullptr) << "No strategy for a logical plan:\n"
<< logical_plan->toString();
// Memorize the created physical plan.
setBestPhysicalForLogical(logical_plan, physical_plan);
return physical_plan;
}
P::PhysicalPtr PhysicalGenerator::optimizePlan() {
std::vector<std::unique_ptr<Rule<P::Physical>>> rules;
rules.emplace_back(new PruneColumns());
for (std::unique_ptr<Rule<P::Physical>> &rule : rules) {
physical_plan_ = rule->apply(physical_plan_);
DVLOG(5) << "After applying rule " << rule->getName() << ":\n"
<< physical_plan_->toString();
}
DVLOG(4) << "Optimized physical plan:\n" << physical_plan_->toString();
#ifdef QUICKSTEP_DEBUG
Validate(physical_plan_);
#endif
return physical_plan_;
}
void PhysicalGenerator::setBestPhysicalForLogical(
const L::LogicalPtr &logical_plan, const P::PhysicalPtr &physical_plan) {
DCHECK(logical_plan != nullptr);
DCHECK(physical_plan != nullptr);
logical_to_physical_map_.emplace(logical_plan, physical_plan);
}
P::PhysicalPtr PhysicalGenerator::createOrGetPhysicalFromLogical(
const L::LogicalPtr &logical_plan) {
DCHECK(logical_plan != nullptr);
// Check if we have created the physical plan.
const std::unordered_map<L::LogicalPtr, P::PhysicalPtr>::const_iterator it =
logical_to_physical_map_.find(logical_plan);
if (it != logical_to_physical_map_.end()) {
return it->second;
}
return generateInitialPlan(logical_plan);
}
} // namespace optimizer
} // namespace quickstep