1
0
Fork 0

disable the use of indexes in certain unsafe situations

This commit is contained in:
Jan Steemann 2015-01-17 17:45:36 +01:00
parent eac7ce5d13
commit 823369c815
2 changed files with 90 additions and 10 deletions

View File

@ -1223,11 +1223,11 @@ class FilterToEnumCollFinder : public WalkerWorker<ExecutionNode> {
Variable const* enumCollVar = nullptr;
// there is an implicit AND between FILTER statements
if (_rangeInfoMapVec == nullptr) {
_rangeInfoMapVec = buildRangeInfo(node->expression()->node(), enumCollVar, attr);
_rangeInfoMapVec = buildRangeInfo(node->expression()->node(), enumCollVar, attr, NODE_TYPE_OPERATOR_BINARY_AND);
}
else {
_rangeInfoMapVec = andCombineRangeInfoMapVecs(_rangeInfoMapVec,
buildRangeInfo(node->expression()->node(), enumCollVar, attr));
buildRangeInfo(node->expression()->node(), enumCollVar, attr, NODE_TYPE_OPERATOR_BINARY_AND));
}
if (_rangeInfoMapVec != nullptr && _mustNotUseRanges) {
@ -1566,13 +1566,18 @@ class FilterToEnumCollFinder : public WalkerWorker<ExecutionNode> {
RangeInfoMapVec* buildRangeInfo (AstNode const* node,
Variable const*& enumCollVar,
std::string& attr) {
std::string& attr,
AstNodeType previousNode) {
bool foundSomething = false;
if (node->type == NODE_TYPE_OPERATOR_BINARY_EQ) {
auto lhs = node->getMember(0);
auto rhs = node->getMember(1);
std::unique_ptr<RangeInfoMap> rim(new RangeInfoMap());
if (rhs->type == NODE_TYPE_ATTRIBUTE_ACCESS) {
if (rhs->type == NODE_TYPE_ATTRIBUTE_ACCESS) {
foundSomething = true;
findVarAndAttr(rhs, enumCollVar, attr);
if (enumCollVar != nullptr) {
std::unordered_set<Variable*> varsUsed
@ -1593,7 +1598,10 @@ class FilterToEnumCollFinder : public WalkerWorker<ExecutionNode> {
}
}
}
if (lhs->type == NODE_TYPE_ATTRIBUTE_ACCESS) {
foundSomething = true;
findVarAndAttr(lhs, enumCollVar, attr);
if (enumCollVar != nullptr) {
std::unordered_set<Variable*> varsUsed
@ -1612,6 +1620,14 @@ class FilterToEnumCollFinder : public WalkerWorker<ExecutionNode> {
}
}
}
if (previousNode == NODE_TYPE_OPERATOR_BINARY_OR && ! foundSomething) {
// disable the use of the range because we may have found something like this,
// which makes using an index for a.x invalid:
// a.x == 1 || RAND() > 0
_mustNotUseRanges = true;
}
return new RangeInfoMapVec(rim.release());
}
@ -1631,7 +1647,9 @@ class FilterToEnumCollFinder : public WalkerWorker<ExecutionNode> {
// Attribute access on the right:
// First find out whether there is a multiple attribute access
// of a variable on the right:
foundSomething = true;
findVarAndAttr(rhs, enumCollVar, attr);
if (enumCollVar != nullptr) {
RangeInfoBound low;
RangeInfoBound high;
@ -1660,7 +1678,9 @@ class FilterToEnumCollFinder : public WalkerWorker<ExecutionNode> {
// Attribute access on the left:
// First find out whether there is a multiple attribute access
// of a variable on the left:
foundSomething = true;
findVarAndAttr(lhs, enumCollVar, attr);
if (enumCollVar != nullptr) {
RangeInfoBound low;
RangeInfoBound high;
@ -1684,21 +1704,33 @@ class FilterToEnumCollFinder : public WalkerWorker<ExecutionNode> {
attr.clear();
}
}
if (previousNode == NODE_TYPE_OPERATOR_BINARY_OR && ! foundSomething) {
// disable the use of the range because we may have found something like this,
// which makes using an index for a.x invalid:
// a.x == 1 || RAND() > 0
_mustNotUseRanges = true;
}
return new RangeInfoMapVec(rim.release());
}
if (node->type == NODE_TYPE_OPERATOR_BINARY_AND) {
// distribute AND into OR
return andCombineRangeInfoMapVecs(buildRangeInfo(node->getMember(0), enumCollVar, attr),
buildRangeInfo(node->getMember(1), enumCollVar, attr));
return andCombineRangeInfoMapVecs(buildRangeInfo(node->getMember(0), enumCollVar, attr, node->type),
buildRangeInfo(node->getMember(1), enumCollVar, attr, node->type));
}
if (node->type == NODE_TYPE_OPERATOR_BINARY_IN) {
auto lhs = node->getMember(0); // enumCollVar
auto rhs = node->getMember(1); // value
std::unique_ptr<RangeInfoMapVec> rimv(new RangeInfoMapVec());
if (lhs->type == NODE_TYPE_ATTRIBUTE_ACCESS) {
if (lhs->type == NODE_TYPE_ATTRIBUTE_ACCESS) {
foundSomething = true;
findVarAndAttr(lhs, enumCollVar, attr);
if (enumCollVar != nullptr) {
std::unordered_set<Variable*> varsUsed
= Ast::getReferencedVariables(rhs);
@ -1735,12 +1767,20 @@ class FilterToEnumCollFinder : public WalkerWorker<ExecutionNode> {
}
}
}
if (previousNode == NODE_TYPE_OPERATOR_BINARY_OR && ! foundSomething) {
// disable the use of the range because we may have found something like this,
// which makes using an index for a.x invalid:
// a.x == 1 || RAND() > 0
_mustNotUseRanges = true;
}
return rimv.release();
}
if (node->type == NODE_TYPE_OPERATOR_BINARY_OR) {
return orCombineRangeInfoMapVecs(buildRangeInfo(node->getMember(0), enumCollVar, attr),
buildRangeInfo(node->getMember(1), enumCollVar, attr));
return orCombineRangeInfoMapVecs(buildRangeInfo(node->getMember(0), enumCollVar, attr, node->type),
buildRangeInfo(node->getMember(1), enumCollVar, attr, node->type));
}
// default case

View File

@ -969,6 +969,46 @@ function optimizerIndexesTestSuite () {
assertEqual([ 1 ], results.json, query);
assertEqual(0, results.stats.scannedFull);
assertTrue(results.stats.scannedIndex > 0);
},
////////////////////////////////////////////////////////////////////////////////
/// @brief test index usage
////////////////////////////////////////////////////////////////////////////////
testIndexOrNoIndexBecauseOfFunctions : function () {
var queries = [
"FOR i IN " + c.name() + " FILTER i.value == 1 || RAND() >= -1 RETURN i.value",
"FOR i IN " + c.name() + " FILTER i.value == 1 || RAND() >= -1 RETURN i.value",
"FOR i IN " + c.name() + " FILTER i.value == 1 || RAND() != -1 RETURN i.value",
"FOR i IN " + c.name() + " FILTER i.value == 1 || RAND() <= 10 RETURN i.value",
"FOR i IN " + c.name() + " FILTER i.value == 1 || RAND() < 10 RETURN i.value",
"FOR i IN " + c.name() + " FILTER i.value == 1 || PASSTHRU(true) == true RETURN i.value",
"FOR i IN " + c.name() + " FILTER i.value == 1 || 1 + PASSTHRU(2) == 3 RETURN i.value",
"FOR i IN " + c.name() + " FILTER i.value == 1 || 1 + PASSTHRU(2) RETURN i.value",
"FOR i IN " + c.name() + " FILTER RAND() >= -1 || i.value == 1 RETURN i.value",
"FOR i IN " + c.name() + " FILTER RAND() >= -1 || i.value == 1 RETURN i.value",
"FOR i IN " + c.name() + " FILTER RAND() != -1 || i.value == 1 RETURN i.value",
"FOR i IN " + c.name() + " FILTER RAND() <= 10 || i.value == 1 RETURN i.value",
"FOR i IN " + c.name() + " FILTER RAND() < 10 || i.value == 1 RETURN i.value",
"FOR i IN " + c.name() + " FILTER PASSTHRU(true) == true RETURN i.value",
"FOR i IN " + c.name() + " FILTER 1 + PASSTHRU(2) == 3 || i.value == 1 RETURN i.value",
"FOR i IN " + c.name() + " FILTER 1 + PASSTHRU(2) || i.value == 1 RETURN i.value",
"FOR i IN " + c.name() + " FILTER i.value IN [ 1, 2 ] || RAND() >= -1 RETURN i.value",
"FOR i IN " + c.name() + " FILTER RAND() >= -1 || i.value IN [ 1, 2 ] RETURN i.value"
];
queries.forEach(function(query) {
var plan = AQL_EXPLAIN(query).plan;
var nodeTypes = plan.nodes.map(function(node) {
return node.type;
});
assertEqual(-1, nodeTypes.indexOf("IndexRangeNode"), query);
var results = AQL_EXECUTE(query);
assertEqual(2000, results.json.length);
assertEqual(0, results.stats.scannedIndex);
assertTrue(results.stats.scannedFull > 0);
});
}
};