mirror of https://gitee.com/bigwinds/arangodb
Merge branch 'aql2' of ssh://github.com/triAGENS/ArangoDB into aql2
Conflicts: arangod/Aql/OptimizerRules.cpp
This commit is contained in:
commit
4ae076db40
|
@ -32,6 +32,7 @@
|
|||
#include "Aql/AstNode.h"
|
||||
#include "Aql/ExecutionNode.h"
|
||||
#include "Aql/Expression.h"
|
||||
#include "Aql/Optimizer.h"
|
||||
#include "Aql/Query.h"
|
||||
#include "Aql/Variable.h"
|
||||
#include "Aql/WalkerWorker.h"
|
||||
|
@ -116,6 +117,33 @@ ExecutionPlan* ExecutionPlan::instanciateFromJson (Ast* ast,
|
|||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief export to JSON, returns an AUTOFREE Json object
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
triagens::basics::Json ExecutionPlan::toJson (TRI_memory_zone_t* zone,
|
||||
bool verbose) const {
|
||||
triagens::basics::Json result = _root->toJson(zone, verbose);
|
||||
|
||||
// set up rules
|
||||
triagens::basics::Json rules(Json::List);
|
||||
auto const&& appliedRules = Optimizer::translateRules(_appliedRules);
|
||||
for (auto r : appliedRules) {
|
||||
rules.add(Json(r));
|
||||
}
|
||||
result.set("rules", rules);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief get a list of all applied rules
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
std::vector<std::string> ExecutionPlan::getAppliedRules () const {
|
||||
return Optimizer::translateRules(_appliedRules);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief get a node by its id
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
@ -1122,11 +1150,12 @@ class CloneNodeAdder : public WalkerWorker<ExecutionNode> {
|
|||
}
|
||||
};
|
||||
|
||||
ExecutionPlan* ExecutionPlan::clone (){
|
||||
ExecutionPlan* ExecutionPlan::clone () {
|
||||
auto plan = new ExecutionPlan();
|
||||
try {
|
||||
plan->_root = _root->clone();
|
||||
plan->_nextId = _nextId;
|
||||
plan->_appliedRules = _appliedRules;
|
||||
CloneNodeAdder adder(plan);
|
||||
plan->_root->walk(&adder);
|
||||
if (! adder.success) {
|
||||
|
|
|
@ -31,9 +31,10 @@
|
|||
#define ARANGODB_AQL_EXECUTION_PLAN_H 1
|
||||
|
||||
#include "Basics/Common.h"
|
||||
#include "arangod/Aql/ExecutionNode.h"
|
||||
#include "arangod/Aql/ModificationOptions.h"
|
||||
#include "arangod/Aql/Query.h"
|
||||
#include "Aql/ExecutionNode.h"
|
||||
#include "Aql/ModificationOptions.h"
|
||||
#include "Aql/Query.h"
|
||||
#include "BasicsC/json.h"
|
||||
|
||||
namespace triagens {
|
||||
namespace aql {
|
||||
|
@ -93,10 +94,22 @@ namespace triagens {
|
|||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
triagens::basics::Json toJson (TRI_memory_zone_t* zone,
|
||||
bool verbose) const {
|
||||
return _root->toJson(zone, verbose);
|
||||
bool verbose) const;
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief note that an optimizer rule was applied
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
inline void addAppliedRule (int level) {
|
||||
_appliedRules.push_back(level);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief get a list of all applied rules
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
std::vector<std::string> getAppliedRules () const;
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief return the next value for a node id
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
@ -375,6 +388,12 @@ namespace triagens {
|
|||
|
||||
std::unordered_map<VariableId, ExecutionNode*> _varSetBy;
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief which optimizer rules were applied for a plan
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
std::vector<int> _appliedRules;
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief flag to indicate whether the variable usage is computed
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
|
|
@ -149,7 +149,6 @@ namespace triagens {
|
|||
std::vector<Variable*> const&,
|
||||
std::vector<RegisterId> const&);
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief check whether this is a simple expression.
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
|
|
@ -56,6 +56,29 @@ Optimizer::Optimizer () {
|
|||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// @brief add a plan to the optimizer
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
bool Optimizer::addPlan (ExecutionPlan* plan,
|
||||
int level,
|
||||
bool wasModified) {
|
||||
TRI_ASSERT(plan != nullptr);
|
||||
|
||||
_newPlans.push_back(plan, level);
|
||||
|
||||
if (wasModified) {
|
||||
// register which rules modified / created the plan
|
||||
plan->addAppliedRule(_currentRule);
|
||||
}
|
||||
|
||||
if (_newPlans.size() > maxNumberOfPlans) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// @brief the actual optimization
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
@ -75,15 +98,14 @@ int Optimizer::createPlans (ExecutionPlan* plan,
|
|||
_plans.clear();
|
||||
_plans.push_back(plan, 0);
|
||||
|
||||
_newPlans.clear();
|
||||
|
||||
// int pass = 1;
|
||||
while (leastDoneLevel < maxRuleLevel) {
|
||||
/*
|
||||
std::cout << "Entering pass " << pass << " of query optimization..."
|
||||
<< std::endl;
|
||||
*/
|
||||
// This vector holds the plans we have created in this pass:
|
||||
PlanList newPlans;
|
||||
|
||||
// Find variable usage for all old plans now:
|
||||
for (auto p : _plans.list) {
|
||||
if (! p->varUsageComputed()) {
|
||||
|
@ -106,7 +128,7 @@ int Optimizer::createPlans (ExecutionPlan* plan,
|
|||
int level;
|
||||
auto p = _plans.pop_front(level);
|
||||
if (level == maxRuleLevel) {
|
||||
newPlans.push_back(p, level); // nothing to do, just keep it
|
||||
_newPlans.push_back(p, level); // nothing to do, just keep it
|
||||
}
|
||||
else { // find next rule
|
||||
auto it = _rules.upper_bound(level);
|
||||
|
@ -122,13 +144,15 @@ int Optimizer::createPlans (ExecutionPlan* plan,
|
|||
// we picked a disabled rule
|
||||
level = it->first;
|
||||
|
||||
newPlans.push_back(p, level); // nothing to do, just keep it
|
||||
_newPlans.push_back(p, level); // nothing to do, just keep it
|
||||
// now try next
|
||||
continue;
|
||||
}
|
||||
|
||||
_currentRule = it->second.level;
|
||||
|
||||
try {
|
||||
res = it->second.func(this, p, it->first, newPlans);
|
||||
res = it->second.func(this, p, &(it->second));
|
||||
}
|
||||
catch (...) {
|
||||
delete p;
|
||||
|
@ -144,7 +168,7 @@ int Optimizer::createPlans (ExecutionPlan* plan,
|
|||
// a good-enough plan is probably every plan with costs below some
|
||||
// defined threshold. this requires plan costs to be calculated here
|
||||
}
|
||||
_plans.steal(newPlans);
|
||||
_plans.steal(_newPlans);
|
||||
leastDoneLevel = maxRuleLevel;
|
||||
for (auto l : _plans.levelDone) {
|
||||
if (l < leastDoneLevel) {
|
||||
|
@ -159,6 +183,8 @@ int Optimizer::createPlans (ExecutionPlan* plan,
|
|||
}
|
||||
}
|
||||
|
||||
TRI_ASSERT(_plans.size() >= 1);
|
||||
|
||||
estimatePlans();
|
||||
sortPlans();
|
||||
/*
|
||||
|
@ -174,6 +200,26 @@ int Optimizer::createPlans (ExecutionPlan* plan,
|
|||
return TRI_ERROR_NO_ERROR;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief translate a list of rule ids into rule name
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
std::vector<std::string> Optimizer::translateRules (std::vector<int> const& rules) {
|
||||
std::vector<std::string> names;
|
||||
|
||||
for (auto r : rules) {
|
||||
auto it = _rules.find(r);
|
||||
if (it != _rules.end()) {
|
||||
names.emplace_back((*it).second.name);
|
||||
}
|
||||
}
|
||||
return names;
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// --SECTION-- private methods
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief estimatePlans
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
|
|
@ -40,8 +40,40 @@ namespace triagens {
|
|||
// -----------------------------------------------------------------------------
|
||||
|
||||
class Optimizer {
|
||||
|
||||
|
||||
public:
|
||||
|
||||
struct Rule;
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief type of an optimizer rule function, the function gets an
|
||||
/// optimiser, an ExecutionPlan, and the current rule. it has
|
||||
/// to append one or more plans to the resulting deque. This must
|
||||
/// include the original plan if it ought to be kept. The rule has to
|
||||
/// set the level of the appended plan to the largest level of rule
|
||||
/// that ought to be considered as done to indicate which rule is to be
|
||||
/// applied next.
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
typedef std::function<int(Optimizer*, ExecutionPlan*, Rule const*)> RuleFunction;
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief type of an optimizer rule
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
struct Rule {
|
||||
std::string name;
|
||||
RuleFunction func;
|
||||
int level;
|
||||
|
||||
Rule () = delete;
|
||||
|
||||
Rule (std::string const& name, RuleFunction func, int level)
|
||||
: name(name),
|
||||
func(func),
|
||||
level(level) {
|
||||
}
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief the following struct keeps a list (deque) of ExecutionPlan*
|
||||
|
@ -167,38 +199,6 @@ namespace triagens {
|
|||
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief type of an optimizer rule function, the function gets an
|
||||
/// optimiser, an ExecutionPlan, the current level of this rule and
|
||||
/// has to append one or more plans to the resulting deque. This must
|
||||
/// include the original plan if it ought to be kept. The rule has to
|
||||
/// set the level of the appended plan to the largest level of rule
|
||||
/// that ought to be considered as done to indicate which rule is to be
|
||||
/// applied next.
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
typedef std::function<int(Optimizer* opt,
|
||||
ExecutionPlan* plan,
|
||||
int level,
|
||||
PlanList& out)>
|
||||
RuleFunction;
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief type of an optimizer rule
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
struct Rule {
|
||||
std::string name;
|
||||
RuleFunction func;
|
||||
int level;
|
||||
|
||||
Rule (std::string const& name, RuleFunction f, int l)
|
||||
: name(name),
|
||||
func(f),
|
||||
level(l) {
|
||||
}
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief maximal number of plans to produce:
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
@ -233,6 +233,15 @@ namespace triagens {
|
|||
int createPlans (ExecutionPlan* p,
|
||||
std::vector<std::string> const&);
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief add a plan to the optimizer
|
||||
/// returns false if there are already enough plans, true otherwise
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
bool addPlan (ExecutionPlan*,
|
||||
int,
|
||||
bool);
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief getBest, ownership of the plan remains with the optimizer
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
@ -268,7 +277,6 @@ namespace triagens {
|
|||
_plans.list.clear();
|
||||
_plans.levelDone.clear();
|
||||
|
||||
// std::cout << res->toJson(TRI_UNKNOWN_MEM_ZONE, false).toString() << "\n";
|
||||
return res;
|
||||
}
|
||||
|
||||
|
@ -284,6 +292,12 @@ namespace triagens {
|
|||
return res;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief translate a list of rule ids into rule name
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
static std::vector<std::string> translateRules (std::vector<int> const&);
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// --SECTION-- private methods
|
||||
// -----------------------------------------------------------------------------
|
||||
|
@ -313,7 +327,7 @@ namespace triagens {
|
|||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
static void registerRule (std::string const& name,
|
||||
RuleFunction f,
|
||||
RuleFunction func,
|
||||
int level) {
|
||||
if (_ruleLookup.find(name) != _ruleLookup.end()) {
|
||||
// duplicate rule names are not allowed
|
||||
|
@ -326,7 +340,7 @@ namespace triagens {
|
|||
THROW_ARANGO_EXCEPTION_MESSAGE(TRI_ERROR_INTERNAL, "duplicate optimizer rule level");
|
||||
}
|
||||
|
||||
_rules.insert(std::make_pair(level, Rule(name, f, level)));
|
||||
_rules.insert(std::make_pair(level, Rule(name, func, level)));
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
@ -359,6 +373,18 @@ namespace triagens {
|
|||
|
||||
PlanList _plans;
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief current list of plans (while applying optimizer rules)
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
PlanList _newPlans;
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief currently active rule (during optimization)
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
int _currentRule;
|
||||
|
||||
};
|
||||
|
||||
} // namespace aql
|
||||
|
|
|
@ -45,9 +45,8 @@ using EN = triagens::aql::ExecutionNode;
|
|||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
int triagens::aql::removeRedundantSorts (Optimizer* opt,
|
||||
ExecutionPlan* plan,
|
||||
int level,
|
||||
Optimizer::PlanList& out) {
|
||||
ExecutionPlan* plan,
|
||||
Optimizer::Rule const* rule) {
|
||||
std::vector<ExecutionNode*> nodes = plan->findNodesOfType(triagens::aql::ExecutionNode::SORT, true);
|
||||
std::unordered_set<ExecutionNode*> toUnlink;
|
||||
|
||||
|
@ -97,7 +96,7 @@ int triagens::aql::removeRedundantSorts (Optimizer* opt,
|
|||
plan->findVarUsage();
|
||||
}
|
||||
|
||||
out.push_back(plan, level);
|
||||
opt->addPlan(plan, rule->level, ! toUnlink.empty());
|
||||
|
||||
return TRI_ERROR_NO_ERROR;
|
||||
}
|
||||
|
@ -111,8 +110,8 @@ int triagens::aql::removeRedundantSorts (Optimizer* opt,
|
|||
|
||||
int triagens::aql::removeUnnecessaryFiltersRule (Optimizer* opt,
|
||||
ExecutionPlan* plan,
|
||||
int level,
|
||||
Optimizer::PlanList& out) {
|
||||
Optimizer::Rule const* rule) {
|
||||
bool modified = false;
|
||||
std::unordered_set<ExecutionNode*> toUnlink;
|
||||
// should we enter subqueries??
|
||||
std::vector<ExecutionNode*> nodes = plan->findNodesOfType(triagens::aql::ExecutionNode::FILTER, true);
|
||||
|
@ -149,6 +148,7 @@ int triagens::aql::removeUnnecessaryFiltersRule (Optimizer* opt,
|
|||
// filter is always true
|
||||
// remove filter node and merge with following node
|
||||
toUnlink.insert(n);
|
||||
modified = true;
|
||||
}
|
||||
else {
|
||||
// filter is always false
|
||||
|
@ -156,6 +156,7 @@ int triagens::aql::removeUnnecessaryFiltersRule (Optimizer* opt,
|
|||
auto noResults = new NoResultsNode(plan->nextId());
|
||||
plan->registerNode(noResults);
|
||||
plan->replaceNode(n, noResults);
|
||||
modified = true;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -164,7 +165,7 @@ int triagens::aql::removeUnnecessaryFiltersRule (Optimizer* opt,
|
|||
plan->findVarUsage();
|
||||
}
|
||||
|
||||
out.push_back(plan, level);
|
||||
opt->addPlan(plan, rule->level, modified);
|
||||
|
||||
return TRI_ERROR_NO_ERROR;
|
||||
}
|
||||
|
@ -178,8 +179,7 @@ int triagens::aql::removeUnnecessaryFiltersRule (Optimizer* opt,
|
|||
|
||||
int triagens::aql::moveCalculationsUpRule (Optimizer* opt,
|
||||
ExecutionPlan* plan,
|
||||
int level,
|
||||
Optimizer::PlanList& out) {
|
||||
Optimizer::Rule const* rule) {
|
||||
std::vector<ExecutionNode*> nodes = plan->findNodesOfType(triagens::aql::ExecutionNode::CALCULATION, true);
|
||||
bool modified = false;
|
||||
|
||||
|
@ -243,7 +243,7 @@ int triagens::aql::moveCalculationsUpRule (Optimizer* opt,
|
|||
plan->findVarUsage();
|
||||
}
|
||||
|
||||
out.push_back(plan, level);
|
||||
opt->addPlan(plan, rule->level, modified);
|
||||
|
||||
return TRI_ERROR_NO_ERROR;
|
||||
}
|
||||
|
@ -258,8 +258,7 @@ int triagens::aql::moveCalculationsUpRule (Optimizer* opt,
|
|||
|
||||
int triagens::aql::moveFiltersUpRule (Optimizer* opt,
|
||||
ExecutionPlan* plan,
|
||||
int level,
|
||||
Optimizer::PlanList& out) {
|
||||
Optimizer::Rule const* rule) {
|
||||
std::vector<ExecutionNode*> nodes = plan->findNodesOfType(triagens::aql::ExecutionNode::FILTER, true);
|
||||
bool modified = false;
|
||||
|
||||
|
@ -323,7 +322,7 @@ int triagens::aql::moveFiltersUpRule (Optimizer* opt,
|
|||
plan->findVarUsage();
|
||||
}
|
||||
|
||||
out.push_back(plan, level);
|
||||
opt->addPlan(plan, rule->level, modified);
|
||||
|
||||
return TRI_ERROR_NO_ERROR;
|
||||
}
|
||||
|
@ -335,8 +334,7 @@ int triagens::aql::moveFiltersUpRule (Optimizer* opt,
|
|||
|
||||
int triagens::aql::removeUnnecessaryCalculationsRule (Optimizer* opt,
|
||||
ExecutionPlan* plan,
|
||||
int level,
|
||||
Optimizer::PlanList& out) {
|
||||
Optimizer::Rule const* rule) {
|
||||
std::vector<ExecutionNode*> nodes
|
||||
= plan->findNodesOfType(triagens::aql::ExecutionNode::CALCULATION, true);
|
||||
std::unordered_set<ExecutionNode*> toUnlink;
|
||||
|
@ -366,7 +364,7 @@ int triagens::aql::removeUnnecessaryCalculationsRule (Optimizer* opt,
|
|||
plan->findVarUsage();
|
||||
}
|
||||
|
||||
out.push_back(plan, level);
|
||||
opt->addPlan(plan, rule->level, ! toUnlink.empty());
|
||||
|
||||
return TRI_ERROR_NO_ERROR;
|
||||
}
|
||||
|
@ -376,20 +374,19 @@ int triagens::aql::removeUnnecessaryCalculationsRule (Optimizer* opt,
|
|||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
class FilterToEnumCollFinder : public WalkerWorker<ExecutionNode> {
|
||||
RangesInfo* _ranges;
|
||||
RangesInfo* _ranges;
|
||||
Optimizer* _opt;
|
||||
ExecutionPlan* _plan;
|
||||
std::unordered_set<VariableId> _varIds;
|
||||
Optimizer::PlanList* _out;
|
||||
bool _canThrow;
|
||||
int _level;
|
||||
|
||||
public:
|
||||
|
||||
FilterToEnumCollFinder (ExecutionPlan* plan, Variable const * var, Optimizer::PlanList* out, int level)
|
||||
: _plan(plan),
|
||||
_out(out),
|
||||
_canThrow(false),
|
||||
_level(level) {
|
||||
FilterToEnumCollFinder (Optimizer* opt, ExecutionPlan* plan, Variable const* var)
|
||||
: _opt(opt),
|
||||
_plan(plan),
|
||||
_canThrow(false) {
|
||||
_ranges = new RangesInfo();
|
||||
_varIds.insert(var->id);
|
||||
};
|
||||
|
@ -416,7 +413,7 @@ class FilterToEnumCollFinder : public WalkerWorker<ExecutionNode> {
|
|||
auto var = node->getVariablesSetHere()[0]; // should only be 1
|
||||
auto map = _ranges->find(var->name); // check if we have any ranges with this var
|
||||
|
||||
if (!map.empty()) {
|
||||
if (! map.empty()) {
|
||||
// check the first components of <map> against indexes of <node> . . .
|
||||
std::unordered_set<std::string> attrs;
|
||||
|
||||
|
@ -433,7 +430,7 @@ class FilterToEnumCollFinder : public WalkerWorker<ExecutionNode> {
|
|||
}
|
||||
|
||||
if (! _canThrow) {
|
||||
if (! valid){ // ranges are not valid . . .
|
||||
if (! valid) { // ranges are not valid . . .
|
||||
|
||||
auto newPlan = _plan->clone();
|
||||
try {
|
||||
|
@ -442,7 +439,7 @@ class FilterToEnumCollFinder : public WalkerWorker<ExecutionNode> {
|
|||
auto noRes = new NoResultsNode(newPlan->nextId());
|
||||
newPlan->registerNode(noRes);
|
||||
newPlan->insertDependency(x, noRes);
|
||||
_out->push_back(newPlan, 0);
|
||||
_opt->addPlan(newPlan, _level, true);
|
||||
}
|
||||
}
|
||||
catch (...) {
|
||||
|
@ -495,7 +492,7 @@ class FilterToEnumCollFinder : public WalkerWorker<ExecutionNode> {
|
|||
node->collection(), node->outVariable(), idx, rangeInfo);
|
||||
newPlan->registerNode(newNode);
|
||||
newPlan->replaceNode(newPlan->getNodeById(node->id()), newNode);
|
||||
_out->push_back(newPlan, _level);
|
||||
_opt->addPlan(newPlan, _level, true);
|
||||
}
|
||||
catch (...) {
|
||||
delete newPlan;
|
||||
|
@ -625,9 +622,8 @@ class FilterToEnumCollFinder : public WalkerWorker<ExecutionNode> {
|
|||
|
||||
int triagens::aql::useIndexRange (Optimizer* opt,
|
||||
ExecutionPlan* plan,
|
||||
int level,
|
||||
Optimizer::PlanList& out) {
|
||||
out.push_back(plan, level);
|
||||
Optimizer::Rule const* rule) {
|
||||
opt->addPlan(plan, rule->level, false);
|
||||
|
||||
std::vector<ExecutionNode*> nodes
|
||||
= plan->findNodesOfType(triagens::aql::ExecutionNode::FILTER, true);
|
||||
|
@ -636,19 +632,18 @@ int triagens::aql::useIndexRange (Optimizer* opt,
|
|||
auto nn = static_cast<FilterNode*>(n);
|
||||
auto invars = nn->getVariablesUsedHere();
|
||||
TRI_ASSERT(invars.size() == 1);
|
||||
FilterToEnumCollFinder finder(plan, invars[0], &out, level);
|
||||
FilterToEnumCollFinder finder(opt, plan, invars[0]);
|
||||
nn->walk(&finder);
|
||||
}
|
||||
|
||||
return TRI_ERROR_NO_ERROR;
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief analyse the sortnode and its calculation nodes
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
class sortAnalysis
|
||||
{
|
||||
|
||||
class sortAnalysis {
|
||||
using ECN = triagens::aql::EnumerateCollectionNode;
|
||||
|
||||
typedef std::pair<ECN::IndexMatchVec, RangeInfoVec> Range_IndexPair;
|
||||
|
@ -773,18 +768,18 @@ public:
|
|||
class sortToIndexNode : public WalkerWorker<ExecutionNode> {
|
||||
using ECN = triagens::aql::EnumerateCollectionNode;
|
||||
|
||||
Optimizer* _opt;
|
||||
ExecutionPlan* _plan;
|
||||
Optimizer::PlanList& _out;
|
||||
sortAnalysis* _sortNode;
|
||||
int _level;
|
||||
|
||||
public:
|
||||
sortToIndexNode (ExecutionPlan* plan,
|
||||
Optimizer::PlanList& out,
|
||||
sortToIndexNode (Optimizer* opt,
|
||||
ExecutionPlan* plan,
|
||||
sortAnalysis* Node,
|
||||
int level)
|
||||
: _plan(plan),
|
||||
_out(out),
|
||||
: _opt(opt),
|
||||
_plan(plan),
|
||||
_sortNode(Node),
|
||||
_level(level) {
|
||||
}
|
||||
|
@ -792,12 +787,13 @@ class sortToIndexNode : public WalkerWorker<ExecutionNode> {
|
|||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief if the sort is already done by an indexrange, remove the sort.
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
bool handleIndexRangeNode(IndexRangeNode* node) {
|
||||
auto variableName = node->getVariablesSetHere()[0]->name;
|
||||
auto result = _sortNode->getAttrsForVariableName(variableName);
|
||||
|
||||
if (node->MatchesIndex(result.first)) {
|
||||
_sortNode->removeSortNodeFromPlan(_plan);
|
||||
_sortNode->removeSortNodeFromPlan(_plan);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
@ -805,8 +801,8 @@ class sortToIndexNode : public WalkerWorker<ExecutionNode> {
|
|||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief check whether we can sort via an index.
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
bool handleEnumerateCollectionNode(EnumerateCollectionNode* node, int level)
|
||||
{
|
||||
|
||||
bool handleEnumerateCollectionNode(EnumerateCollectionNode* node, int level) {
|
||||
auto variableName = node->getVariablesSetHere()[0]->name;
|
||||
auto result = _sortNode->getAttrsForVariableName(variableName);
|
||||
|
||||
|
@ -834,7 +830,7 @@ class sortToIndexNode : public WalkerWorker<ExecutionNode> {
|
|||
if (idx.fullmatch) { // if the index superseedes the sort, remove it.
|
||||
_sortNode->removeSortNodeFromPlan(newPlan);
|
||||
}
|
||||
_out.push_back(newPlan, level);
|
||||
_opt->addPlan(newPlan, level, true);
|
||||
}
|
||||
catch (...) {
|
||||
delete newPlan;
|
||||
|
@ -842,11 +838,7 @@ class sortToIndexNode : public WalkerWorker<ExecutionNode> {
|
|||
}
|
||||
|
||||
}
|
||||
/*for (auto x : result.second) {
|
||||
for (auto y : x) {
|
||||
delete y;
|
||||
}
|
||||
}*/
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -896,20 +888,19 @@ class sortToIndexNode : public WalkerWorker<ExecutionNode> {
|
|||
|
||||
int triagens::aql::useIndexForSort (Optimizer* opt,
|
||||
ExecutionPlan* plan,
|
||||
int level,
|
||||
Optimizer::PlanList& out) {
|
||||
Optimizer::Rule const* rule) {
|
||||
std::vector<ExecutionNode*> nodes
|
||||
= plan->findNodesOfType(triagens::aql::ExecutionNode::SORT, true);
|
||||
for (auto n : nodes) {
|
||||
auto thisSortNode = static_cast<SortNode*>(n);
|
||||
sortAnalysis node(thisSortNode);
|
||||
if (node.isAnalyzeable()) {
|
||||
sortToIndexNode finder(plan, out, &node, level);
|
||||
sortToIndexNode finder(opt, plan, &node, rule->level);
|
||||
thisSortNode->walk(&finder);/// todo auf der dependency anfangen
|
||||
}
|
||||
}
|
||||
|
||||
out.push_back(plan, level);
|
||||
|
||||
opt->addPlan(plan, rule->level, false);
|
||||
|
||||
return TRI_ERROR_NO_ERROR;
|
||||
}
|
||||
|
@ -954,9 +945,7 @@ static bool nextPermutationTuple (std::vector<size_t>& data,
|
|||
|
||||
int triagens::aql::interchangeAdjacentEnumerations (Optimizer* opt,
|
||||
ExecutionPlan* plan,
|
||||
int level,
|
||||
Optimizer::PlanList& out) {
|
||||
|
||||
Optimizer::Rule const* rule) {
|
||||
std::vector<ExecutionNode*> nodes
|
||||
= plan->findNodesOfType(triagens::aql::ExecutionNode::ENUMERATE_COLLECTION,
|
||||
true);
|
||||
|
@ -1009,7 +998,8 @@ int triagens::aql::interchangeAdjacentEnumerations (Optimizer* opt,
|
|||
// plan, we need to compute all possible permutations of all of them,
|
||||
// independently. This is why we need to compute all permutation tuples.
|
||||
|
||||
out.push_back(plan, level);
|
||||
opt->addPlan(plan, rule->level, false);
|
||||
|
||||
if (! starts.empty()) {
|
||||
nextPermutationTuple(permTuple, starts); // will never return false
|
||||
do {
|
||||
|
@ -1050,10 +1040,7 @@ int triagens::aql::interchangeAdjacentEnumerations (Optimizer* opt,
|
|||
}
|
||||
|
||||
// OK, the new plan is ready, let's report it:
|
||||
out.push_back(newPlan, level);
|
||||
|
||||
// Stop if this gets out of hand:
|
||||
if (out.size() > opt->maxNumberOfPlans) {
|
||||
if (! opt->addPlan(newPlan, rule->level, true)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -46,7 +46,7 @@ namespace triagens {
|
|||
/// - sorts that are covered by earlier sorts will be removed
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
int removeRedundantSorts (Optimizer*, ExecutionPlan*, int level, Optimizer::PlanList&);
|
||||
int removeRedundantSorts (Optimizer*, ExecutionPlan*, Optimizer::Rule const*);
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief remove all unnecessary filters
|
||||
|
@ -55,7 +55,7 @@ namespace triagens {
|
|||
/// - filters that are always false will be replaced by a NoResults node
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
int removeUnnecessaryFiltersRule (Optimizer*, ExecutionPlan*, int level, Optimizer::PlanList&);
|
||||
int removeUnnecessaryFiltersRule (Optimizer*, ExecutionPlan*, Optimizer::Rule const*);
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief move calculations up in the plan
|
||||
|
@ -64,7 +64,7 @@ namespace triagens {
|
|||
/// avoid redundant calculations in inner loops
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
int moveCalculationsUpRule (Optimizer*, ExecutionPlan*, int level, Optimizer::PlanList&);
|
||||
int moveCalculationsUpRule (Optimizer*, ExecutionPlan*, Optimizer::Rule const*);
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief move filters up in the plan
|
||||
|
@ -74,34 +74,31 @@ namespace triagens {
|
|||
/// filters are not pushed beyond limits
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
int moveFiltersUpRule (Optimizer*, ExecutionPlan*, int level, Optimizer::PlanList&);
|
||||
int moveFiltersUpRule (Optimizer*, ExecutionPlan*, Optimizer::Rule const*);
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief remove a CalculationNode that is never needed
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
int removeUnnecessaryCalculationsRule (Optimizer*, ExecutionPlan*, int level, Optimizer::PlanList&);
|
||||
int removeUnnecessaryCalculationsRule (Optimizer*, ExecutionPlan*, Optimizer::Rule const*);
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief prefer IndexRange nodes over EnumerateCollection nodes
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
int useIndexRange (Optimizer*, ExecutionPlan*, int level, Optimizer::PlanList&);
|
||||
int useIndexRange (Optimizer*, ExecutionPlan*, Optimizer::Rule const*);
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief try to use the index for sorting
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
int useIndexForSort (Optimizer*, ExecutionPlan*, int level, Optimizer::PlanList&);
|
||||
int useIndexForSort (Optimizer*, ExecutionPlan*, Optimizer::Rule const*);
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief interchange adjacent EnumerateCollectionNodes in all possible ways
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
int interchangeAdjacentEnumerations ( Optimizer* opt,
|
||||
ExecutionPlan* plan,
|
||||
int level,
|
||||
Optimizer::PlanList& out);
|
||||
int interchangeAdjacentEnumerations (Optimizer*, ExecutionPlan*, Optimizer::Rule const*);
|
||||
|
||||
} // namespace aql
|
||||
} // namespace triagens
|
||||
|
|
|
@ -375,10 +375,10 @@ QueryResult Query::explain () {
|
|||
TRI_ASSERT(plan != nullptr);
|
||||
|
||||
trx.commit();
|
||||
//triagens::basic::Json json(triagens::basic::Json::Array);
|
||||
|
||||
QueryResult result(TRI_ERROR_NO_ERROR);
|
||||
result.json = plan->toJson(TRI_UNKNOWN_MEM_ZONE, false).steal(); //json();
|
||||
|
||||
delete plan;
|
||||
|
||||
return result;
|
||||
|
|
Loading…
Reference in New Issue