1
0
Fork 0

fixes for explainer and condition

This commit is contained in:
Jan Steemann 2015-10-08 16:22:52 +02:00
parent c6c6ba8f6f
commit 6a4e9658c5
5 changed files with 268 additions and 199 deletions

View File

@ -667,7 +667,10 @@ namespace triagens {
////////////////////////////////////////////////////////////////////////////////
inline AstNode* getMemberUnchecked (size_t i) const throw() {
return members.at(i);
#ifdef TRI_ENABLE_MAINTAINER_MODE
TRI_ASSERT(i < members.size());
#endif
return members[i];
}
////////////////////////////////////////////////////////////////////////////////

View File

@ -426,12 +426,15 @@ ConditionPart::ConditionPartCompareResult const ConditionPart::ResultsTable[3][7
}
};
void Condition::optimize (ExecutionPlan* plan) {
typedef std::vector<std::pair<size_t, AttributeSideType>> UsagePositionType;
typedef std::unordered_map<std::string, UsagePositionType> AttributeUsageType;
typedef std::unordered_map<Variable const*, AttributeUsageType> VariableUsageType;
////////////////////////////////////////////////////////////////////////////////
/// @brief registers an attribute access for a particular (collection) variable
////////////////////////////////////////////////////////////////////////////////
void Condition::storeAttributeAccess (VariableUsageType& variableUsage,
AstNode const* node,
size_t position,
AttributeSideType side) {
auto storeAttributeAccess = [] (VariableUsageType& variableUsage, AstNode const* node, size_t position, AttributeSideType side) {
std::pair<Variable const*, std::vector<triagens::basics::AttributeName>> result;
if (! node->isAttributeAccessForVariable(result)) {
@ -468,8 +471,13 @@ void Condition::optimize (ExecutionPlan* plan) {
dst.emplace_back(position, side);
}
}
};
}
////////////////////////////////////////////////////////////////////////////////
/// @brief optimize the condition expression tree
////////////////////////////////////////////////////////////////////////////////
void Condition::optimize (ExecutionPlan* plan) {
if (_root == nullptr) {
return;
}
@ -478,13 +486,15 @@ void Condition::optimize (ExecutionPlan* plan) {
TRI_ASSERT(_root->type == NODE_TYPE_OPERATOR_NARY_OR);
// handle sub nodes or top-level OR node
size_t const n = _root->numMembers();
size_t n = _root->numMembers();
size_t r = 0;
for (size_t i = 0; i < n; ++i) { // foreach OR-Node
auto andNode = _root->getMemberUnchecked(i);
while (r < n) { // foreach OR-Node
bool retry = false;
auto andNode = _root->getMemberUnchecked(r);
TRI_ASSERT(andNode->type == NODE_TYPE_OPERATOR_NARY_AND);
restartThisOrItem:
restartThisOrItem:
size_t const andNumMembers = andNode->numMembers();
// deduplicate all IN arrays
@ -492,6 +502,14 @@ void Condition::optimize (ExecutionPlan* plan) {
deduplicateInOperation(andNode->getMemberUnchecked(j));
}
if (andNumMembers <= 1) {
// simple AND item with 0 or 1 members. nothing to do
++r;
continue;
}
TRI_ASSERT(andNumMembers > 1);
// move IN operation to the front to make comparison code below simpler
andNode->sortMembers([] (AstNode const* lhs, AstNode const* rhs) -> bool {
if (lhs->type == NODE_TYPE_OPERATOR_BINARY_IN) {
@ -506,7 +524,6 @@ void Condition::optimize (ExecutionPlan* plan) {
return (lhs < rhs); // compare pointers to have a deterministic order
});
if (andNumMembers > 1) {
// optimization is only necessary if an AND node has multiple members
VariableUsageType variableUsage;
@ -603,7 +620,8 @@ void Condition::optimize (ExecutionPlan* plan) {
if (inNode->numMembers() == 0) {
// no values left after merging -> IMPOSSIBLE
_root->removeMemberUnchecked(i);
_root->removeMemberUnchecked(r);
retry = true;
goto fastForwardToNextOrItem;
}
@ -627,8 +645,8 @@ void Condition::optimize (ExecutionPlan* plan) {
// impossible condition
// j = positions.size();
// we remove this one, so fast forward the loops to their end:
_root->removeMemberUnchecked(i);
/// i -= 1; <- wenn wir das ohne goto machen...
_root->removeMemberUnchecked(r);
retry = true;
goto fastForwardToNextOrItem;
}
case CompareResult::SELF_CONTAINED_IN_OTHER: {
@ -667,12 +685,17 @@ void Condition::optimize (ExecutionPlan* plan) {
} // cross compare sub-and-nodes
} // foreach sub-and-node
fastForwardToNextOrItem:
continue;
fastForwardToNextOrItem:
if (retry) {
// number of root sub-nodes has probably changed.
// now recalculate the number and don't modify r!
n = _root->numMembers();
}
else {
// root nodes hasn't changed. go to next sub-node!
++r;
}
}
}
////////////////////////////////////////////////////////////////////////////////

View File

@ -125,6 +125,16 @@ namespace triagens {
class Condition {
// -----------------------------------------------------------------------------
// --SECTION-- private typedefs
// -----------------------------------------------------------------------------
private:
typedef std::vector<std::pair<size_t, AttributeSideType>> UsagePositionType;
typedef std::unordered_map<std::string, UsagePositionType> AttributeUsageType;
typedef std::unordered_map<Variable const*, AttributeUsageType> VariableUsageType;
// -----------------------------------------------------------------------------
// --SECTION-- constructors / destructors
// -----------------------------------------------------------------------------
@ -211,6 +221,15 @@ namespace triagens {
void normalize (ExecutionPlan* plan);
////////////////////////////////////////////////////////////////////////////////
/// @brief registers an attribute access for a particular (collection) variable
////////////////////////////////////////////////////////////////////////////////
void storeAttributeAccess (VariableUsageType&,
AstNode const*,
size_t,
AttributeSideType);
////////////////////////////////////////////////////////////////////////////////
/// @brief optimize the condition expression tree
////////////////////////////////////////////////////////////////////////////////

View File

@ -191,7 +191,7 @@ function printIndexes (indexes) {
stringBuilder.appendLine(" " + value("none"));
}
else {
var maxIdLen = String("Id").length;
var maxIdLen = String("By").length;
var maxCollectionLen = String("Collection").length;
var maxUniqueLen = String("Unique").length;
var maxSparseLen = String("Sparse").length;
@ -216,7 +216,7 @@ function printIndexes (indexes) {
maxCollectionLen = l;
}
});
var line = " " + pad(1 + maxIdLen - String("Id").length) + header("Id") + " " +
var line = " " + pad(1 + maxIdLen - String("By").length) + header("By") + " " +
header("Type") + pad(1 + maxTypeLen - "Type".length) + " " +
header("Collection") + pad(1 + maxCollectionLen - "Collection".length) + " " +
header("Unique") + pad(1 + maxUniqueLen - "Unique".length) + " " +
@ -232,7 +232,13 @@ function printIndexes (indexes) {
var sparsity = (indexes[i].hasOwnProperty("sparse") ? (indexes[i].sparse ? "true" : "false") : "n/a");
var fields = indexes[i].fields.map(attribute).join(", ");
var fieldsLen = indexes[i].fields.map(attributeUncolored).join(", ").length;
var ranges = "[ " + indexes[i].ranges + " ]";
var ranges;
if (indexes[i].hasOwnProperty("condition")) {
ranges = indexes[i].condition;
}
else {
ranges = "[ " + indexes[i].ranges + " ]";
}
var selectivity = (indexes[i].hasOwnProperty("selectivityEstimate") ?
(indexes[i].selectivityEstimate * 100).toFixed(2) + " %" :
"n/a"
@ -378,8 +384,6 @@ function processQuery (query, explain) {
references[node.subNodes[0].subNodes[0].name] = node.subNodes[0].subNodes[1];
}
return buildExpression(node.subNodes[1]);
case "verticalizer":
return buildExpression(node.subNodes[0]);
case "user function call":
return func(node.name) + "(" + ((node.subNodes && node.subNodes[0].subNodes) || [ ]).map(buildExpression).join(", ") + ")" + " " + annotation("/* user-defined function */");
case "function call":
@ -416,6 +420,10 @@ function processQuery (query, explain) {
return buildExpression(node.subNodes[0]) + " && " + buildExpression(node.subNodes[1]);
case "ternary":
return buildExpression(node.subNodes[0]) + " ? " + buildExpression(node.subNodes[1]) + " : " + buildExpression(node.subNodes[2]);
case "n-ary or":
return node.subNodes.map(function(sub) { return buildExpression(sub); }).join(" || ");
case "n-ary and":
return node.subNodes.map(function(sub) { return buildExpression(sub); }).join(" && ");
default:
return "unhandled node type (" + node.type + ")";
}
@ -486,11 +494,14 @@ function processQuery (query, explain) {
case "IndexNode":
collectionVariables[node.outVariable.id] = node.collection;
var types = [ ];
node.indexes.forEach(function (idx) {
node.indexes.forEach(function (idx, i) {
types.push((idx.reverse ? "reverse " : "") + idx.type + " index scan");
idx.collection = node.collection;
idx.node = node.id;
idx.ranges = [ ];
var condition = "";
if (node.condition.type === 'n-ary or') {
idx.condition = buildExpression(node.condition.subNodes[i]);
}
indexes.push(idx);
});
return keyword("FOR") + " " + variableName(node.outVariable) + " " + keyword("IN") + " " + collection(node.collection) + " " + annotation("/* " + types.join(", ") + " */");

View File

@ -190,7 +190,7 @@ function printIndexes (indexes) {
stringBuilder.appendLine(" " + value("none"));
}
else {
var maxIdLen = String("Id").length;
var maxIdLen = String("By").length;
var maxCollectionLen = String("Collection").length;
var maxUniqueLen = String("Unique").length;
var maxSparseLen = String("Sparse").length;
@ -215,7 +215,7 @@ function printIndexes (indexes) {
maxCollectionLen = l;
}
});
var line = " " + pad(1 + maxIdLen - String("Id").length) + header("Id") + " " +
var line = " " + pad(1 + maxIdLen - String("By").length) + header("By") + " " +
header("Type") + pad(1 + maxTypeLen - "Type".length) + " " +
header("Collection") + pad(1 + maxCollectionLen - "Collection".length) + " " +
header("Unique") + pad(1 + maxUniqueLen - "Unique".length) + " " +
@ -231,7 +231,13 @@ function printIndexes (indexes) {
var sparsity = (indexes[i].hasOwnProperty("sparse") ? (indexes[i].sparse ? "true" : "false") : "n/a");
var fields = indexes[i].fields.map(attribute).join(", ");
var fieldsLen = indexes[i].fields.map(attributeUncolored).join(", ").length;
var ranges = "[ " + indexes[i].ranges + " ]";
var ranges;
if (indexes[i].hasOwnProperty("condition")) {
ranges = indexes[i].condition;
}
else {
ranges = "[ " + indexes[i].ranges + " ]";
}
var selectivity = (indexes[i].hasOwnProperty("selectivityEstimate") ?
(indexes[i].selectivityEstimate * 100).toFixed(2) + " %" :
"n/a"
@ -377,8 +383,6 @@ function processQuery (query, explain) {
references[node.subNodes[0].subNodes[0].name] = node.subNodes[0].subNodes[1];
}
return buildExpression(node.subNodes[1]);
case "verticalizer":
return buildExpression(node.subNodes[0]);
case "user function call":
return func(node.name) + "(" + ((node.subNodes && node.subNodes[0].subNodes) || [ ]).map(buildExpression).join(", ") + ")" + " " + annotation("/* user-defined function */");
case "function call":
@ -415,6 +419,10 @@ function processQuery (query, explain) {
return buildExpression(node.subNodes[0]) + " && " + buildExpression(node.subNodes[1]);
case "ternary":
return buildExpression(node.subNodes[0]) + " ? " + buildExpression(node.subNodes[1]) + " : " + buildExpression(node.subNodes[2]);
case "n-ary or":
return node.subNodes.map(function(sub) { return buildExpression(sub); }).join(" || ");
case "n-ary and":
return node.subNodes.map(function(sub) { return buildExpression(sub); }).join(" && ");
default:
return "unhandled node type (" + node.type + ")";
}
@ -485,11 +493,16 @@ function processQuery (query, explain) {
case "IndexNode":
collectionVariables[node.outVariable.id] = node.collection;
var types = [ ];
node.indexes.forEach(function (idx) {
node.indexes.forEach(function (idx, i) {
types.push((idx.reverse ? "reverse " : "") + idx.type + " index scan");
idx.collection = node.collection;
idx.node = node.id;
idx.ranges = [ ];
if (node.condition.type === 'n-ary or') {
idx.condition = buildExpression(node.condition.subNodes[i]);
}
else {
idx.conditionn = "";
}
indexes.push(idx);
});
return keyword("FOR") + " " + variableName(node.outVariable) + " " + keyword("IN") + " " + collection(node.collection) + " " + annotation("/* " + types.join(", ") + " */");