mirror of https://gitee.com/bigwinds/arangodb
Merge branch 'aql2' of ssh://github.com/triAGENS/ArangoDB into aql2
This commit is contained in:
commit
8919c138c7
|
@ -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.");
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -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();
|
||||||
|
|
|
@ -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
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
Loading…
Reference in New Issue