mirror of https://gitee.com/bigwinds/arangodb
disable the use of indexes in certain unsafe situations
This commit is contained in:
parent
eac7ce5d13
commit
823369c815
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
});
|
||||
}
|
||||
|
||||
};
|
||||
|
|
Loading…
Reference in New Issue