1
0
Fork 0

Merge branch 'aql2' of ssh://github.com/triAGENS/ArangoDB into aql2

This commit is contained in:
Max Neunhoeffer 2014-08-21 16:55:05 +02:00
commit 8919c138c7
5 changed files with 190 additions and 13 deletions

View File

@ -1053,7 +1053,7 @@ void ExecutionPlan::replaceNode (ExecutionNode* oldNode,
newNode->addDependency(x); newNode->addDependency(x);
} }
auto&& oldNodeParents = oldNode->getParents(); auto oldNodeParents = oldNode->getParents();
for (auto oldNodeParent : oldNodeParents) { for (auto oldNodeParent : oldNodeParents) {
if(! oldNodeParent->replaceDependency(oldNode, newNode)){ if(! oldNodeParent->replaceDependency(oldNode, newNode)){
THROW_ARANGO_EXCEPTION_MESSAGE(TRI_ERROR_INTERNAL, THROW_ARANGO_EXCEPTION_MESSAGE(TRI_ERROR_INTERNAL,
@ -1073,7 +1073,7 @@ void ExecutionPlan::insertDependency (ExecutionNode* oldNode,
TRI_ASSERT(newNode->getDependencies().size() == 1); TRI_ASSERT(newNode->getDependencies().size() == 1);
TRI_ASSERT(oldNode != _root); TRI_ASSERT(oldNode != _root);
auto&& oldDeps = oldNode->getDependencies(); auto oldDeps = oldNode->getDependencies();
if (! oldNode->replaceDependency(oldDeps[0], newNode)) { if (! oldNode->replaceDependency(oldDeps[0], newNode)) {
THROW_ARANGO_EXCEPTION_MESSAGE(TRI_ERROR_INTERNAL, THROW_ARANGO_EXCEPTION_MESSAGE(TRI_ERROR_INTERNAL,
"Could not replace dependencies of an old node."); "Could not replace dependencies of an old node.");

View File

@ -50,7 +50,11 @@ Optimizer::Optimizer () {
registerRule(removeUnnecessaryFiltersRule, 10000); registerRule(removeUnnecessaryFiltersRule, 10000);
// move calculations up the dependency chain (to pull them out of inner loops etc.) // move calculations up the dependency chain (to pull them out of inner loops etc.)
// registerRule(moveCalculationsUpRule, 1000); registerRule(moveCalculationsUpRule, 1001);
// move filters up the dependency chain (to make result sets as small as possible
// as early as possible)
registerRule(moveFiltersUpRule, 1000);
// remove calculations that are never necessary // remove calculations that are never necessary
registerRule(removeUnnecessaryCalculationsRule, 999); registerRule(removeUnnecessaryCalculationsRule, 999);

View File

@ -116,7 +116,7 @@ namespace triagens {
/// @brief appends all the plans to the target and clears *this at the same time /// @brief appends all the plans to the target and clears *this at the same time
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
void appendTo (vector<ExecutionPlan*>& target) { void appendTo (std::vector<ExecutionPlan*>& target) {
while (list.size() > 0) { while (list.size() > 0) {
auto p = list.front(); auto p = list.front();
list.pop_front(); list.pop_front();
@ -226,7 +226,7 @@ namespace triagens {
/// @brief getPlans, ownership of the plans remains with the optimizer /// @brief getPlans, ownership of the plans remains with the optimizer
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
vector<ExecutionPlan*>& getPlans () { std::vector<ExecutionPlan*>& getPlans () {
return _plans; return _plans;
} }
@ -252,8 +252,8 @@ namespace triagens {
/// the optimizer will forget about them! /// the optimizer will forget about them!
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
vector<ExecutionPlan*> stealPlans () { std::vector<ExecutionPlan*> stealPlans () {
vector<ExecutionPlan*> res; std::vector<ExecutionPlan*> res;
res.swap(_plans); res.swap(_plans);
return res; return res;
} }
@ -292,13 +292,13 @@ namespace triagens {
/// @brief the rules database /// @brief the rules database
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
vector<Rule> _rules; std::vector<Rule> _rules;
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
/// @brief the current set of plans to be optimised /// @brief the current set of plans to be optimised
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
vector<ExecutionPlan*> _plans; std::vector<ExecutionPlan*> _plans;
}; };

View File

@ -48,7 +48,6 @@ int triagens::aql::removeUnnecessaryFiltersRule (Optimizer* opt,
ExecutionPlan* plan, ExecutionPlan* plan,
Optimizer::PlanList& out, Optimizer::PlanList& out,
bool& keep) { bool& keep) {
keep = true; // plan will always be kept keep = true; // plan will always be kept
std::unordered_set<ExecutionNode*> toUnlink; std::unordered_set<ExecutionNode*> toUnlink;
std::vector<ExecutionNode*> nodes = plan->findNodesOfType(triagens::aql::ExecutionNode::FILTER, true); std::vector<ExecutionNode*> nodes = plan->findNodesOfType(triagens::aql::ExecutionNode::FILTER, true);
@ -97,6 +96,167 @@ int triagens::aql::removeUnnecessaryFiltersRule (Optimizer* opt,
if (! toUnlink.empty()) { if (! toUnlink.empty()) {
plan->unlinkNodes(toUnlink); plan->unlinkNodes(toUnlink);
plan->findVarUsage();
}
return TRI_ERROR_NO_ERROR;
}
////////////////////////////////////////////////////////////////////////////////
/// @brief move calculations up in the plan
/// this rule modifies the plan in place
/// it aims to move up calculations as far up in the plan as possible, to
/// avoid redundant calculations in inner loops
////////////////////////////////////////////////////////////////////////////////
int triagens::aql::moveCalculationsUpRule (Optimizer* opt,
ExecutionPlan* plan,
Optimizer::PlanList& out,
bool& keep) {
keep = true; // plan will always be kept
std::vector<ExecutionNode*> nodes = plan->findNodesOfType(triagens::aql::ExecutionNode::CALCULATION, true);
bool modified = false;
for (auto n : nodes) {
auto nn = static_cast<CalculationNode*>(n);
if (nn->expression()->canThrow()) {
// we will only move expressions up that cannot throw
continue;
}
auto neededVars = n->getVariablesUsedHere();
// sort the list of variables that the expression needs as its input
// (sorting is needed for intersection later)
std::sort(neededVars.begin(), neededVars.end(), &Variable::Comparator);
std::vector<ExecutionNode*> stack;
for (auto dep : n->getDependencies()) {
stack.push_back(dep);
}
while (! stack.empty()) {
auto current = stack.back();
stack.pop_back();
bool found = false;
auto&& varsSet = current->getVariablesSetHere();
for (auto v : varsSet) {
for (auto it = neededVars.begin(); it != neededVars.end(); ++it) {
if ((*it)->id == v->id) {
// shared variable, cannot move up any more
found = true;
break;
}
}
}
if (found) {
// done with optimizing this calculation node
break;
}
auto deps = current->getDependencies();
if (deps.size() != 1) {
// node either has no or more than one dependency. we don't know what to do and must abort
// note: this will also handle Singleton nodes
break;
}
for (auto dep : deps) {
stack.push_back(dep);
}
// first, unlink the calculation from the plan
plan->unlinkNode(n);
// and re-insert into before the current node
plan->insertDependency(current, n);
modified = true;
}
}
if (modified) {
plan->findVarUsage();
}
return TRI_ERROR_NO_ERROR;
}
////////////////////////////////////////////////////////////////////////////////
/// @brief move filters up in the plan
/// this rule modifies the plan in place
/// filters are moved as far up in the plan as possible to make result sets
/// as small as possible as early as possible
/// filters are not pushed beyond limits
////////////////////////////////////////////////////////////////////////////////
int triagens::aql::moveFiltersUpRule (Optimizer* opt,
ExecutionPlan* plan,
Optimizer::PlanList& out,
bool& keep) {
keep = true; // plan will always be kept
std::vector<ExecutionNode*> nodes = plan->findNodesOfType(triagens::aql::ExecutionNode::FILTER, true);
bool modified = false;
for (auto n : nodes) {
auto neededVars = n->getVariablesUsedHere();
TRI_ASSERT(neededVars.size() == 1);
std::vector<ExecutionNode*> stack;
for (auto dep : n->getDependencies()) {
stack.push_back(dep);
}
while (! stack.empty()) {
auto current = stack.back();
stack.pop_back();
if (current->getType() == triagens::aql::ExecutionNode::LIMIT) {
// cannot push a filter beyond a LIMIT node
break;
}
bool found = false;
auto&& varsSet = current->getVariablesSetHere();
for (auto v : varsSet) {
for (auto it = neededVars.begin(); it != neededVars.end(); ++it) {
if ((*it)->id == v->id) {
// shared variable, cannot move up any more
found = true;
break;
}
}
}
if (found) {
// done with optimizing this calculation node
break;
}
auto deps = current->getDependencies();
if (deps.size() != 1) {
// node either has no or more than one dependency. we don't know what to do and must abort
// note: this will also handle Singleton nodes
break;
}
for (auto dep : deps) {
stack.push_back(dep);
}
// first, unlink the filter from the plan
plan->unlinkNode(n);
// and re-insert into before the current node
plan->insertDependency(current, n);
modified = true;
}
}
if (modified) {
plan->findVarUsage();
} }
return TRI_ERROR_NO_ERROR; return TRI_ERROR_NO_ERROR;
@ -136,16 +296,15 @@ int triagens::aql::removeUnnecessaryCalculationsRule (Optimizer* opt,
} }
if (! toUnlink.empty()) { if (! toUnlink.empty()) {
std::cout << "Removing " << toUnlink.size() << " unnecessary "
"CalculationNodes..." << std::endl;
plan->unlinkNodes(toUnlink); plan->unlinkNodes(toUnlink);
plan->findVarUsage();
} }
return TRI_ERROR_NO_ERROR; return TRI_ERROR_NO_ERROR;
} }
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
/// @brief find nodes of a certain type /// @brief prefer IndexRange nodes over EnumerateCollection nodes
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
class CalculationNodeFinder : public WalkerWorker<ExecutionNode> { class CalculationNodeFinder : public WalkerWorker<ExecutionNode> {
@ -158,6 +317,7 @@ class CalculationNodeFinder : public WalkerWorker<ExecutionNode> {
//EnumerateCollectionNode const* _enumColl; //EnumerateCollectionNode const* _enumColl;
public: public:
CalculationNodeFinder (ExecutionPlan* plan, Variable const * var, Optimizer::PlanList& out) CalculationNodeFinder (ExecutionPlan* plan, Variable const * var, Optimizer::PlanList& out)
: _plan(plan), _var(var), _out(out), _prev(nullptr){ : _plan(plan), _var(var), _out(out), _prev(nullptr){
_ranges = new RangesInfo(); _ranges = new RangesInfo();

View File

@ -51,10 +51,23 @@ namespace triagens {
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
/// @brief move calculations up in the plan /// @brief move calculations up in the plan
/// this rule modifies the plan in place
/// it aims to move up calculations as far up in the plan as possible, to
/// avoid redundant calculations in inner loops
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
int moveCalculationsUpRule (Optimizer*, ExecutionPlan*, Optimizer::PlanList&, bool&); int moveCalculationsUpRule (Optimizer*, ExecutionPlan*, Optimizer::PlanList&, bool&);
////////////////////////////////////////////////////////////////////////////////
/// @brief move filters up in the plan
/// this rule modifies the plan in place
/// filters are moved as far up in the plan as possible to make result sets
/// as small as possible as early as possible
/// filters are not pushed beyond limits
////////////////////////////////////////////////////////////////////////////////
int moveFiltersUpRule (Optimizer*, ExecutionPlan*, Optimizer::PlanList&, bool&);
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
/// @brief remove a CalculationNode that is never needed /// @brief remove a CalculationNode that is never needed
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////