mirror of https://gitee.com/bigwinds/arangodb
[3.3] Fix condition finders moving filters past modifications into index nodes (#6328)
This commit is contained in:
parent
6476106048
commit
2bd9887407
|
|
@ -40,29 +40,32 @@ bool ConditionFinder::before(ExecutionNode* en) {
|
|||
case EN::REMOTE:
|
||||
case EN::SUBQUERY:
|
||||
case EN::INDEX:
|
||||
case EN::RETURN:
|
||||
case EN::TRAVERSAL:
|
||||
case EN::SHORTEST_PATH: {
|
||||
// in these cases we simply ignore the intermediate nodes, note
|
||||
// that we have taken care of nodes that could throw exceptions
|
||||
// above.
|
||||
break;
|
||||
}
|
||||
|
||||
case EN::INSERT:
|
||||
case EN::REMOVE:
|
||||
case EN::REPLACE:
|
||||
case EN::UPDATE:
|
||||
case EN::UPSERT:
|
||||
case EN::RETURN:
|
||||
case EN::TRAVERSAL:
|
||||
case EN::SHORTEST_PATH:
|
||||
// in these cases we simply ignore the intermediate nodes, note
|
||||
// that we have taken care of nodes that could throw exceptions
|
||||
// above.
|
||||
break;
|
||||
|
||||
case EN::LIMIT:
|
||||
case EN::LIMIT: {
|
||||
// LIMIT invalidates the sort expression we already found
|
||||
_sorts.clear();
|
||||
_filters.clear();
|
||||
break;
|
||||
}
|
||||
|
||||
case EN::SINGLETON:
|
||||
case EN::NORESULTS:
|
||||
case EN::NORESULTS: {
|
||||
// in all these cases we better abort
|
||||
return true;
|
||||
}
|
||||
|
||||
case EN::FILTER: {
|
||||
std::vector<Variable const*> invars(en->getVariablesUsedHere());
|
||||
|
|
|
|||
|
|
@ -127,14 +127,14 @@ static bool IsSupportedNode(Variable const* pathVar, AstNode const* node) {
|
|||
case NODE_TYPE_OPERATOR_BINARY_IN:
|
||||
case NODE_TYPE_OPERATOR_BINARY_NIN: {
|
||||
// the following types of expressions are not supported
|
||||
// p.edges[0]._from op whatever attribute access
|
||||
// p.edges[0]._from op whatever attribute access
|
||||
// whatever attribute access op p.edges[0]._from
|
||||
AstNode const* lhs = node->getMember(0);
|
||||
AstNode const* rhs = node->getMember(1);
|
||||
|
||||
if (lhs->isAttributeAccessForVariable(pathVar, true)) {
|
||||
// p.xxx op whatever
|
||||
if (rhs->type != NODE_TYPE_VALUE &&
|
||||
if (rhs->type != NODE_TYPE_VALUE &&
|
||||
rhs->type != NODE_TYPE_ARRAY &&
|
||||
rhs->type != NODE_TYPE_OBJECT &&
|
||||
rhs->type != NODE_TYPE_REFERENCE) {
|
||||
|
|
@ -142,7 +142,7 @@ static bool IsSupportedNode(Variable const* pathVar, AstNode const* node) {
|
|||
}
|
||||
} else if (rhs->isAttributeAccessForVariable(pathVar, true)) {
|
||||
// whatever op p.xxx
|
||||
if (lhs->type != NODE_TYPE_VALUE &&
|
||||
if (lhs->type != NODE_TYPE_VALUE &&
|
||||
lhs->type != NODE_TYPE_ARRAY &&
|
||||
lhs->type != NODE_TYPE_OBJECT &&
|
||||
lhs->type != NODE_TYPE_REFERENCE) {
|
||||
|
|
@ -315,7 +315,7 @@ static bool checkPathVariableAccessFeasible(Ast* ast, AstNode* parent,
|
|||
patternStep++;
|
||||
break;
|
||||
}
|
||||
case 3:
|
||||
case 3:
|
||||
if (depth != UINT64_MAX) {
|
||||
// We are in depth pattern.
|
||||
// The first Node we encount HAS to be indexed Access
|
||||
|
|
@ -327,7 +327,7 @@ static bool checkPathVariableAccessFeasible(Ast* ast, AstNode* parent,
|
|||
// Search for the parent having this node.
|
||||
patternStep = 6;
|
||||
parentOfReplace = node;
|
||||
|
||||
|
||||
// we need to know the depth at which a filter condition will
|
||||
// access a path. Otherwise there are too many results
|
||||
TRI_ASSERT(node->numMembers() == 2);
|
||||
|
|
@ -380,7 +380,7 @@ static bool checkPathVariableAccessFeasible(Ast* ast, AstNode* parent,
|
|||
}
|
||||
parentOfReplace = node;
|
||||
replaceIdx = idx;
|
||||
// Ok finally done.
|
||||
// Ok finally done.
|
||||
patternStep++;
|
||||
break;
|
||||
}
|
||||
|
|
@ -505,25 +505,33 @@ bool TraversalConditionFinder::before(ExecutionNode* en) {
|
|||
case EN::REMOTE:
|
||||
case EN::SUBQUERY:
|
||||
case EN::INDEX:
|
||||
case EN::INSERT:
|
||||
case EN::REMOVE:
|
||||
case EN::REPLACE:
|
||||
case EN::UPDATE:
|
||||
case EN::UPSERT:
|
||||
case EN::LIMIT:
|
||||
case EN::RETURN:
|
||||
case EN::SORT:
|
||||
case EN::ENUMERATE_COLLECTION:
|
||||
case EN::LIMIT:
|
||||
case EN::SHORTEST_PATH:
|
||||
case EN::SHORTEST_PATH: {
|
||||
// in these cases we simply ignore the intermediate nodes, note
|
||||
// that we have taken care of nodes that could throw exceptions
|
||||
// above.
|
||||
break;
|
||||
}
|
||||
|
||||
case EN::INSERT:
|
||||
case EN::REMOVE:
|
||||
case EN::REPLACE:
|
||||
case EN::UPDATE:
|
||||
case EN::UPSERT: {
|
||||
// modification invalidates the filter expression we already found
|
||||
_condition = std::make_unique<Condition>(_plan->getAst());
|
||||
_filterVariables.clear();
|
||||
break;
|
||||
}
|
||||
|
||||
case EN::SINGLETON:
|
||||
case EN::NORESULTS:
|
||||
case EN::NORESULTS: {
|
||||
// in all these cases we better abort
|
||||
return true;
|
||||
}
|
||||
|
||||
case EN::FILTER: {
|
||||
std::vector<Variable const*>&& invars = en->getVariablesUsedHere();
|
||||
|
|
@ -587,7 +595,7 @@ bool TraversalConditionFinder::before(ExecutionNode* en) {
|
|||
TRI_ASSERT(andNode->type == NODE_TYPE_OPERATOR_NARY_AND);
|
||||
|
||||
std::unordered_set<Variable const*> varsUsedByCondition;
|
||||
|
||||
|
||||
auto originalFilterConditions = std::make_unique<Condition>(_plan->getAst());
|
||||
for (size_t i = andNode->numMembers(); i > 0; --i) {
|
||||
// Whenever we do not support a of the condition we have to throw it out
|
||||
|
|
@ -602,7 +610,7 @@ bool TraversalConditionFinder::before(ExecutionNode* en) {
|
|||
// For now we only! optimize filter conditions on the path
|
||||
// So we skip all FILTERS not referencing the path
|
||||
andNode->removeMemberUnchecked(i - 1);
|
||||
continue;
|
||||
continue;
|
||||
}
|
||||
|
||||
// now we validate that there is no illegal variable used.
|
||||
|
|
@ -628,7 +636,7 @@ bool TraversalConditionFinder::before(ExecutionNode* en) {
|
|||
|
||||
AstNode* cloned = andNode->getMember(i - 1)->clone(_plan->getAst());
|
||||
int64_t indexedAccessDepth = -1;
|
||||
|
||||
|
||||
size_t swappedIndex = 0;
|
||||
// If we get here we can optimize this condition
|
||||
if (!checkPathVariableAccessFeasible(_plan->getAst(), andNode, i - 1,
|
||||
|
|
@ -646,7 +654,7 @@ bool TraversalConditionFinder::before(ExecutionNode* en) {
|
|||
|
||||
} else {
|
||||
TRI_ASSERT(!conditionIsImpossible);
|
||||
|
||||
|
||||
// remember the original filter conditions if we can remove them later
|
||||
if (indexedAccessDepth == -1) {
|
||||
originalFilterConditions->andCombine(cloned);
|
||||
|
|
@ -655,7 +663,7 @@ bool TraversalConditionFinder::before(ExecutionNode* en) {
|
|||
// is in [0..maxDepth], if the depth is not a concrete value
|
||||
// then indexedAccessDepth would be INT64_MAX
|
||||
originalFilterConditions->andCombine(cloned);
|
||||
|
||||
|
||||
if ((int64_t)options->minDepth < indexedAccessDepth && !isTrueOnNull(cloned, pathVar)) {
|
||||
// do not return paths shorter than the deepest path access
|
||||
// Unless the condition evaluates to true on `null`.
|
||||
|
|
|
|||
|
|
@ -87,9 +87,9 @@ function simpleInboundOutboundSuite () {
|
|||
|
||||
c = db._create(gn + 'v2', { numberOfShards: 7 });
|
||||
c.insert({ _key: "test" });
|
||||
|
||||
|
||||
c = db._createEdgeCollection(gn + 'e', { numberOfShards: 5 });
|
||||
c.insert({ _from: gn + "v2/test", _to: gn + "v1/test" });
|
||||
c.insert({ _from: gn + "v2/test", _to: gn + "v1/test" });
|
||||
},
|
||||
|
||||
tearDown: function () {
|
||||
|
|
@ -2490,7 +2490,62 @@ function complexFilteringSuite () {
|
|||
// 1 Filter On D
|
||||
assertEqual(stats.filtered, 1);
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
testModify: function () {
|
||||
var query = `WITH ${vn}
|
||||
FOR v, e, p IN 1..2 OUTBOUND @start @@ecol
|
||||
UPDATE v WITH {updated: true} IN @@vcol
|
||||
FILTER p.vertices[1].left == true
|
||||
SORT v._key
|
||||
RETURN v._key`;
|
||||
var bindVars = {
|
||||
'@ecol': en,
|
||||
'@vcol': vn,
|
||||
start: vertex.A
|
||||
};
|
||||
var cursor = db._query(query, bindVars);
|
||||
assertEqual(cursor.count(), 3);
|
||||
assertEqual(cursor.toArray(), ['B', 'C', 'F']);
|
||||
var stats = cursor.getExtra().stats;
|
||||
assertEqual(stats.writesExecuted, 6);
|
||||
assertEqual(stats.scannedFull, 0);
|
||||
if (isCluster) {
|
||||
// 1 Primary lookup A
|
||||
// 2 Edge Lookups (A)
|
||||
// 2 Primary lookup B,D
|
||||
// 2 Edge Lookups (2 B) (0 D)
|
||||
// 2 Primary Lookups (C, F)
|
||||
if (mmfilesEngine) {
|
||||
assertTrue(stats.scannedIndex <= 13);
|
||||
} else {
|
||||
assertTrue(stats.scannedIndex <= 7);
|
||||
}
|
||||
} else {
|
||||
// 2 Edge Lookups (A)
|
||||
// 2 Primary (B, D) for Filtering
|
||||
// 2 Edge Lookups (B)
|
||||
// All edges are cached
|
||||
// 1 Primary Lookups A -> B (B cached)
|
||||
// 1 Primary Lookups A -> B -> C (A, B cached)
|
||||
// 1 Primary Lookups A -> B -> F (A, B cached)
|
||||
// With traverser-read-cache
|
||||
// assertEqual(stats.scannedIndex, 9);
|
||||
|
||||
// Without traverser-read-cache
|
||||
assertTrue(stats.scannedIndex <= 28);
|
||||
/*
|
||||
if(mmfilesEngine){
|
||||
assertEqual(stats.scannedIndex, 17);
|
||||
} else {
|
||||
assertEqual(stats.scannedIndex, 13);
|
||||
}
|
||||
*/
|
||||
}
|
||||
// 1 Filter On D
|
||||
assertEqual(stats.filtered, 3);
|
||||
},
|
||||
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -60,18 +60,18 @@ function optimizerIndexesTestSuite () {
|
|||
|
||||
testSameResultsConstAccess : function () {
|
||||
var bind = { doc : { key: "test1" } };
|
||||
var q1 = `RETURN (FOR item IN UnitTestsCollection FILTER (@doc.key == item._key) LIMIT 1 RETURN item)[0]`;
|
||||
var q2 = `LET doc = @doc RETURN (FOR item IN UnitTestsCollection FILTER (doc.key == item._key) LIMIT 1 RETURN item)[0]`;
|
||||
var q1 = `RETURN (FOR item IN UnitTestsCollection FILTER (@doc.key == item._key) LIMIT 1 RETURN item)[0]`;
|
||||
var q2 = `LET doc = @doc RETURN (FOR item IN UnitTestsCollection FILTER (doc.key == item._key) LIMIT 1 RETURN item)[0]`;
|
||||
var q3 = `LET doc = { key: "test1" } RETURN (FOR item IN UnitTestsCollection FILTER (doc.key == item._key) LIMIT 1 RETURN item)[0]`;
|
||||
|
||||
|
||||
var results = AQL_EXECUTE(q1, bind);
|
||||
assertEqual(1, results.json.length);
|
||||
assertEqual("test1", results.json[0]._key);
|
||||
|
||||
|
||||
results = AQL_EXECUTE(q2, bind);
|
||||
assertEqual(1, results.json.length);
|
||||
assertEqual("test1", results.json[0]._key);
|
||||
|
||||
|
||||
results = AQL_EXECUTE(q3);
|
||||
assertEqual(1, results.json.length);
|
||||
assertEqual("test1", results.json[0]._key);
|
||||
|
|
@ -91,7 +91,7 @@ function optimizerIndexesTestSuite () {
|
|||
|
||||
assertEqual("SingletonNode", nodeTypes[0], query);
|
||||
assertNotEqual(-1, nodeTypes.indexOf("IndexNode"), query);
|
||||
|
||||
|
||||
var results = AQL_EXECUTE(query);
|
||||
assertEqual([ 22 ], results.json, query);
|
||||
assertEqual(0, results.stats.scannedFull);
|
||||
|
|
@ -112,7 +112,7 @@ function optimizerIndexesTestSuite () {
|
|||
|
||||
assertEqual("SingletonNode", nodeTypes[0], query);
|
||||
assertNotEqual(-1, nodeTypes.indexOf("IndexNode"), query);
|
||||
|
||||
|
||||
var results = AQL_EXECUTE(query);
|
||||
assertEqual([ ], results.json, query);
|
||||
assertEqual(0, results.stats.scannedFull);
|
||||
|
|
@ -134,7 +134,7 @@ function optimizerIndexesTestSuite () {
|
|||
|
||||
assertEqual("SingletonNode", nodeTypes[0], query);
|
||||
assertNotEqual(-1, nodeTypes.indexOf("IndexNode"), query);
|
||||
|
||||
|
||||
var results = AQL_EXECUTE(query);
|
||||
assertEqual([ 1, 2, 21, 30 ], results.json.sort(), query);
|
||||
assertEqual(0, results.stats.scannedFull);
|
||||
|
|
@ -159,13 +159,13 @@ function optimizerIndexesTestSuite () {
|
|||
|
||||
assertEqual("SingletonNode", nodeTypes[0], query);
|
||||
assertNotEqual(-1, nodeTypes.indexOf("IndexNode"), query);
|
||||
|
||||
|
||||
var results = AQL_EXECUTE(query);
|
||||
assertEqual([ 1, 2, 21, 30 ], results.json.sort(), query);
|
||||
assertEqual(0, results.stats.scannedFull);
|
||||
assertEqual(4, results.stats.scannedIndex);
|
||||
},
|
||||
|
||||
|
||||
testUsePrimaryIdNoDocuments : function () {
|
||||
var values = [ "UnitTestsCollection/test1", "UnitTestsCollection/test2", "UnitTestsCollection/test21", "UnitTestsCollection/test30" ];
|
||||
var query = "FOR i IN " + c.name() + " FILTER i._id IN " + JSON.stringify(values) + " RETURN 1";
|
||||
|
|
@ -180,7 +180,7 @@ function optimizerIndexesTestSuite () {
|
|||
|
||||
assertEqual("SingletonNode", nodeTypes[0], query);
|
||||
assertNotEqual(-1, nodeTypes.indexOf("IndexNode"), query);
|
||||
|
||||
|
||||
var results = AQL_EXECUTE(query);
|
||||
assertEqual([ 1, 1, 1, 1 ], results.json, query);
|
||||
assertEqual(0, results.stats.scannedFull);
|
||||
|
|
@ -202,7 +202,7 @@ function optimizerIndexesTestSuite () {
|
|||
|
||||
assertEqual("SingletonNode", nodeTypes[0], query);
|
||||
assertNotEqual(-1, nodeTypes.indexOf("IndexNode"), query);
|
||||
|
||||
|
||||
var results = AQL_EXECUTE(query);
|
||||
assertEqual([ ], results.json, query);
|
||||
assertEqual(0, results.stats.scannedFull);
|
||||
|
|
@ -226,7 +226,7 @@ function optimizerIndexesTestSuite () {
|
|||
|
||||
assertEqual("SingletonNode", nodeTypes[0], query);
|
||||
assertNotEqual(-1, nodeTypes.indexOf("IndexNode"), query);
|
||||
|
||||
|
||||
var results = AQL_EXECUTE(query);
|
||||
assertEqual([ 6 ], results.json, query);
|
||||
assertEqual(0, results.stats.scannedFull);
|
||||
|
|
@ -246,7 +246,7 @@ function optimizerIndexesTestSuite () {
|
|||
|
||||
assertEqual("SingletonNode", nodeTypes[0], query);
|
||||
assertNotEqual(-1, nodeTypes.indexOf("IndexNode"), query);
|
||||
|
||||
|
||||
var results = AQL_EXECUTE(query);
|
||||
assertEqual([ 1 ], results.json, query);
|
||||
assertEqual(0, results.stats.scannedFull);
|
||||
|
|
@ -267,7 +267,7 @@ function optimizerIndexesTestSuite () {
|
|||
|
||||
assertEqual("SingletonNode", nodeTypes[0], query);
|
||||
assertNotEqual(-1, nodeTypes.indexOf("IndexNode"), query);
|
||||
|
||||
|
||||
var results = AQL_EXECUTE(query);
|
||||
assertEqual([ ], results.json, query);
|
||||
assertEqual(0, results.stats.scannedFull);
|
||||
|
|
@ -289,7 +289,7 @@ function optimizerIndexesTestSuite () {
|
|||
|
||||
assertEqual("SingletonNode", nodeTypes[0], query);
|
||||
assertNotEqual(-1, nodeTypes.indexOf("IndexNode"), query);
|
||||
|
||||
|
||||
var results = AQL_EXECUTE(query);
|
||||
assertEqual([ 1, 2, 21, 30 ], results.json.sort(), query);
|
||||
assertEqual(0, results.stats.scannedFull);
|
||||
|
|
@ -311,7 +311,7 @@ function optimizerIndexesTestSuite () {
|
|||
|
||||
assertEqual("SingletonNode", nodeTypes[0], query);
|
||||
assertNotEqual(-1, nodeTypes.indexOf("IndexNode"), query);
|
||||
|
||||
|
||||
var results = AQL_EXECUTE(query);
|
||||
assertEqual([ 1, 2, 21, 30 ], results.json.sort(), query);
|
||||
assertEqual(0, results.stats.scannedFull);
|
||||
|
|
@ -333,7 +333,7 @@ function optimizerIndexesTestSuite () {
|
|||
|
||||
assertEqual("SingletonNode", nodeTypes[0], query);
|
||||
assertNotEqual(-1, nodeTypes.indexOf("IndexNode"), query);
|
||||
|
||||
|
||||
var results = AQL_EXECUTE(query);
|
||||
assertEqual([ ], results.json, query);
|
||||
assertEqual(0, results.stats.scannedFull);
|
||||
|
|
@ -354,7 +354,7 @@ function optimizerIndexesTestSuite () {
|
|||
|
||||
assertEqual("SingletonNode", nodeTypes[0], query);
|
||||
assertNotEqual(-1, nodeTypes.indexOf("IndexNode"), query);
|
||||
|
||||
|
||||
var results = AQL_EXECUTE(query);
|
||||
assertEqual([ 12 ], results.json, query);
|
||||
assertEqual(0, results.stats.scannedFull);
|
||||
|
|
@ -375,7 +375,7 @@ function optimizerIndexesTestSuite () {
|
|||
|
||||
assertEqual("SingletonNode", nodeTypes[0], query);
|
||||
assertNotEqual(-1, nodeTypes.indexOf("IndexNode"), query);
|
||||
|
||||
|
||||
var results = AQL_EXECUTE(query);
|
||||
assertEqual([ 12 ], results.json, query);
|
||||
assertEqual(0, results.stats.scannedFull);
|
||||
|
|
@ -396,7 +396,7 @@ function optimizerIndexesTestSuite () {
|
|||
|
||||
assertEqual("SingletonNode", nodeTypes[0], query);
|
||||
assertNotEqual(-1, nodeTypes.indexOf("IndexNode"), query);
|
||||
|
||||
|
||||
var results = AQL_EXECUTE(query);
|
||||
assertEqual([ 12 ], results.json, query);
|
||||
assertEqual(0, results.stats.scannedFull);
|
||||
|
|
@ -417,7 +417,7 @@ function optimizerIndexesTestSuite () {
|
|||
|
||||
assertEqual("SingletonNode", nodeTypes[0], query);
|
||||
assertNotEqual(-1, nodeTypes.indexOf("IndexNode"), query);
|
||||
|
||||
|
||||
var results = AQL_EXECUTE(query);
|
||||
assertEqual([ 12 ], results.json, query);
|
||||
assertEqual(0, results.stats.scannedFull);
|
||||
|
|
@ -438,7 +438,7 @@ function optimizerIndexesTestSuite () {
|
|||
|
||||
assertEqual("SingletonNode", nodeTypes[0], query);
|
||||
assertNotEqual(-1, nodeTypes.indexOf("IndexNode"), query);
|
||||
|
||||
|
||||
var results = AQL_EXECUTE(query);
|
||||
assertEqual([ 12 ], results.json, query);
|
||||
assertEqual(0, results.stats.scannedFull);
|
||||
|
|
@ -459,7 +459,7 @@ function optimizerIndexesTestSuite () {
|
|||
|
||||
assertEqual("SingletonNode", nodeTypes[0], query);
|
||||
assertNotEqual(-1, nodeTypes.indexOf("IndexNode"), query);
|
||||
|
||||
|
||||
var results = AQL_EXECUTE(query);
|
||||
assertEqual([ 12 ], results.json, query);
|
||||
assertEqual(0, results.stats.scannedFull);
|
||||
|
|
@ -480,7 +480,7 @@ function optimizerIndexesTestSuite () {
|
|||
|
||||
assertEqual("SingletonNode", nodeTypes[0], query);
|
||||
assertNotEqual(-1, nodeTypes.indexOf("IndexNode"), query);
|
||||
|
||||
|
||||
var results = AQL_EXECUTE(query);
|
||||
assertEqual([ 12 ], results.json, query);
|
||||
assertEqual(0, results.stats.scannedFull);
|
||||
|
|
@ -501,7 +501,7 @@ function optimizerIndexesTestSuite () {
|
|||
|
||||
assertEqual("SingletonNode", nodeTypes[0], query);
|
||||
assertNotEqual(-1, nodeTypes.indexOf("IndexNode"), query);
|
||||
|
||||
|
||||
var results = AQL_EXECUTE(query);
|
||||
assertEqual([ 12 ], results.json, query);
|
||||
assertEqual(0, results.stats.scannedFull);
|
||||
|
|
@ -543,7 +543,7 @@ function optimizerIndexesTestSuite () {
|
|||
|
||||
assertEqual("SingletonNode", nodeTypes[0], query);
|
||||
assertNotEqual(-1, nodeTypes.indexOf("IndexNode"), query);
|
||||
|
||||
|
||||
var results = AQL_EXECUTE(query);
|
||||
assertEqual([ 12 ], results.json, query);
|
||||
assertEqual(0, results.stats.scannedFull);
|
||||
|
|
@ -577,7 +577,7 @@ function optimizerIndexesTestSuite () {
|
|||
// retry without index
|
||||
var idx = c.lookupIndex({ type: "skiplist", fields: [ "value" ] });
|
||||
c.dropIndex(idx);
|
||||
|
||||
|
||||
results = AQL_EXECUTE(query);
|
||||
assertEqual([ ], results.json, query);
|
||||
assertTrue(results.stats.scannedFull > 0);
|
||||
|
|
@ -611,7 +611,7 @@ function optimizerIndexesTestSuite () {
|
|||
// retry without index
|
||||
var idx = c.lookupIndex({ type: "skiplist", fields: [ "value" ] });
|
||||
c.dropIndex(idx);
|
||||
|
||||
|
||||
results = AQL_EXECUTE(query);
|
||||
assertEqual([ 'one', 'one' ], results.json, query);
|
||||
assertTrue(results.stats.scannedFull > 0);
|
||||
|
|
@ -642,11 +642,11 @@ function optimizerIndexesTestSuite () {
|
|||
assertEqual([ 'one', 'one' ], results.json, query);
|
||||
assertEqual(0, results.stats.scannedFull);
|
||||
assertTrue(results.stats.scannedIndex > 0);
|
||||
|
||||
|
||||
// retry without index
|
||||
var idx = c.lookupIndex({ type: "skiplist", fields: [ "value" ] });
|
||||
c.dropIndex(idx);
|
||||
|
||||
|
||||
results = AQL_EXECUTE(query);
|
||||
assertEqual([ 'one', 'one' ], results.json, query);
|
||||
assertTrue(results.stats.scannedFull > 0);
|
||||
|
|
@ -677,11 +677,11 @@ function optimizerIndexesTestSuite () {
|
|||
assertEqual([ ], results.json, query);
|
||||
assertEqual(0, results.stats.scannedFull);
|
||||
assertEqual(0, results.stats.scannedIndex);
|
||||
|
||||
|
||||
// retry without index
|
||||
var idx = c.lookupIndex({ type: "skiplist", fields: [ "value" ] });
|
||||
c.dropIndex(idx);
|
||||
|
||||
|
||||
results = AQL_EXECUTE(query);
|
||||
assertEqual([ ], results.json, query);
|
||||
assertEqual(0, results.stats.scannedFull);
|
||||
|
|
@ -711,11 +711,11 @@ function optimizerIndexesTestSuite () {
|
|||
assertEqual([ ], results.json, query);
|
||||
assertEqual(0, results.stats.scannedFull);
|
||||
assertTrue(results.stats.scannedIndex > 0);
|
||||
|
||||
|
||||
// retry without index
|
||||
var idx = c.lookupIndex({ type: "skiplist", fields: [ "value" ] });
|
||||
c.dropIndex(idx);
|
||||
|
||||
|
||||
results = AQL_EXECUTE(query);
|
||||
assertEqual([ ], results.json, query);
|
||||
assertTrue(results.stats.scannedFull > 0);
|
||||
|
|
@ -829,7 +829,7 @@ function optimizerIndexesTestSuite () {
|
|||
assertEqual(0, results.stats.scannedFull);
|
||||
assertTrue(results.stats.scannedIndex > 0);
|
||||
},
|
||||
|
||||
|
||||
testUseIndexSimpleNoDocuments : function () {
|
||||
var query = "FOR i IN " + c.name() + " FILTER i.value >= 10 SORT i.value LIMIT 10 RETURN 1";
|
||||
|
||||
|
|
@ -982,15 +982,15 @@ function optimizerIndexesTestSuite () {
|
|||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
testMultipleSubqueries : function () {
|
||||
var query = "LET a = (FOR x IN " + c.name() + " FILTER x._key == 'test1' RETURN x._key) " +
|
||||
"LET b = (FOR x IN " + c.name() + " FILTER x._key == 'test2' RETURN x._key) " +
|
||||
"LET c = (FOR x IN " + c.name() + " FILTER x._key == 'test3' RETURN x._key) " +
|
||||
"LET d = (FOR x IN " + c.name() + " FILTER x._key == 'test4' RETURN x._key) " +
|
||||
"LET e = (FOR x IN " + c.name() + " FILTER x._key == 'test5' RETURN x._key) " +
|
||||
"LET f = (FOR x IN " + c.name() + " FILTER x._key == 'test6' RETURN x._key) " +
|
||||
"LET g = (FOR x IN " + c.name() + " FILTER x._key == 'test7' RETURN x._key) " +
|
||||
"LET h = (FOR x IN " + c.name() + " FILTER x._key == 'test8' RETURN x._key) " +
|
||||
"LET i = (FOR x IN " + c.name() + " FILTER x._key == 'test9' RETURN x._key) " +
|
||||
var query = "LET a = (FOR x IN " + c.name() + " FILTER x._key == 'test1' RETURN x._key) " +
|
||||
"LET b = (FOR x IN " + c.name() + " FILTER x._key == 'test2' RETURN x._key) " +
|
||||
"LET c = (FOR x IN " + c.name() + " FILTER x._key == 'test3' RETURN x._key) " +
|
||||
"LET d = (FOR x IN " + c.name() + " FILTER x._key == 'test4' RETURN x._key) " +
|
||||
"LET e = (FOR x IN " + c.name() + " FILTER x._key == 'test5' RETURN x._key) " +
|
||||
"LET f = (FOR x IN " + c.name() + " FILTER x._key == 'test6' RETURN x._key) " +
|
||||
"LET g = (FOR x IN " + c.name() + " FILTER x._key == 'test7' RETURN x._key) " +
|
||||
"LET h = (FOR x IN " + c.name() + " FILTER x._key == 'test8' RETURN x._key) " +
|
||||
"LET i = (FOR x IN " + c.name() + " FILTER x._key == 'test9' RETURN x._key) " +
|
||||
"LET j = (FOR x IN " + c.name() + " FILTER x._key == 'test10' RETURN x._key) " +
|
||||
"RETURN [ a, b, c, d, e, f, g, h, i, j ]";
|
||||
|
||||
|
|
@ -1023,7 +1023,7 @@ function optimizerIndexesTestSuite () {
|
|||
|
||||
var results = AQL_EXECUTE(query);
|
||||
assertEqual(0, results.stats.scannedFull);
|
||||
assertNotEqual(0, results.stats.scannedIndex);
|
||||
assertNotEqual(0, results.stats.scannedIndex);
|
||||
assertEqual([ [ [ 'test1' ], [ 'test2' ], [ 'test3' ], [ 'test4' ], [ 'test5' ], [ 'test6' ], [ 'test7' ], [ 'test8' ], [ 'test9' ], [ 'test10' ] ] ], results.json);
|
||||
},
|
||||
|
||||
|
|
@ -1033,15 +1033,15 @@ function optimizerIndexesTestSuite () {
|
|||
|
||||
testMultipleSubqueriesMultipleIndexes : function () {
|
||||
c.ensureHashIndex("value"); // now we have a hash and a skiplist index
|
||||
var query = "LET a = (FOR x IN " + c.name() + " FILTER x.value == 1 RETURN x._key) " +
|
||||
"LET b = (FOR x IN " + c.name() + " FILTER x.value == 2 RETURN x._key) " +
|
||||
"LET c = (FOR x IN " + c.name() + " FILTER x.value == 3 RETURN x._key) " +
|
||||
"LET d = (FOR x IN " + c.name() + " FILTER x.value == 4 RETURN x._key) " +
|
||||
"LET e = (FOR x IN " + c.name() + " FILTER x.value == 5 RETURN x._key) " +
|
||||
"LET f = (FOR x IN " + c.name() + " FILTER x.value == 6 RETURN x._key) " +
|
||||
"LET g = (FOR x IN " + c.name() + " FILTER x.value == 7 RETURN x._key) " +
|
||||
"LET h = (FOR x IN " + c.name() + " FILTER x.value == 8 RETURN x._key) " +
|
||||
"LET i = (FOR x IN " + c.name() + " FILTER x.value == 9 RETURN x._key) " +
|
||||
var query = "LET a = (FOR x IN " + c.name() + " FILTER x.value == 1 RETURN x._key) " +
|
||||
"LET b = (FOR x IN " + c.name() + " FILTER x.value == 2 RETURN x._key) " +
|
||||
"LET c = (FOR x IN " + c.name() + " FILTER x.value == 3 RETURN x._key) " +
|
||||
"LET d = (FOR x IN " + c.name() + " FILTER x.value == 4 RETURN x._key) " +
|
||||
"LET e = (FOR x IN " + c.name() + " FILTER x.value == 5 RETURN x._key) " +
|
||||
"LET f = (FOR x IN " + c.name() + " FILTER x.value == 6 RETURN x._key) " +
|
||||
"LET g = (FOR x IN " + c.name() + " FILTER x.value == 7 RETURN x._key) " +
|
||||
"LET h = (FOR x IN " + c.name() + " FILTER x.value == 8 RETURN x._key) " +
|
||||
"LET i = (FOR x IN " + c.name() + " FILTER x.value == 9 RETURN x._key) " +
|
||||
"LET j = (FOR x IN " + c.name() + " FILTER x.value == 10 RETURN x._key) " +
|
||||
"RETURN [ a, b, c, d, e, f, g, h, i, j ]";
|
||||
|
||||
|
|
@ -1079,7 +1079,7 @@ function optimizerIndexesTestSuite () {
|
|||
|
||||
var results = AQL_EXECUTE(query);
|
||||
assertEqual(0, results.stats.scannedFull);
|
||||
assertNotEqual(0, results.stats.scannedIndex);
|
||||
assertNotEqual(0, results.stats.scannedIndex);
|
||||
assertEqual([ [ [ 'test1' ], [ 'test2' ], [ 'test3' ], [ 'test4' ], [ 'test5' ], [ 'test6' ], [ 'test7' ], [ 'test8' ], [ 'test9' ], [ 'test10' ] ] ], results.json);
|
||||
},
|
||||
|
||||
|
|
@ -1090,15 +1090,15 @@ function optimizerIndexesTestSuite () {
|
|||
testMultipleSubqueriesHashIndexes : function () {
|
||||
c.dropIndex(c.getIndexes()[1]); // drop skiplist index
|
||||
c.ensureHashIndex("value");
|
||||
var query = "LET a = (FOR x IN " + c.name() + " FILTER x.value == 1 RETURN x._key) " +
|
||||
"LET b = (FOR x IN " + c.name() + " FILTER x.value == 2 RETURN x._key) " +
|
||||
"LET c = (FOR x IN " + c.name() + " FILTER x.value == 3 RETURN x._key) " +
|
||||
"LET d = (FOR x IN " + c.name() + " FILTER x.value == 4 RETURN x._key) " +
|
||||
"LET e = (FOR x IN " + c.name() + " FILTER x.value == 5 RETURN x._key) " +
|
||||
"LET f = (FOR x IN " + c.name() + " FILTER x.value == 6 RETURN x._key) " +
|
||||
"LET g = (FOR x IN " + c.name() + " FILTER x.value == 7 RETURN x._key) " +
|
||||
"LET h = (FOR x IN " + c.name() + " FILTER x.value == 8 RETURN x._key) " +
|
||||
"LET i = (FOR x IN " + c.name() + " FILTER x.value == 9 RETURN x._key) " +
|
||||
var query = "LET a = (FOR x IN " + c.name() + " FILTER x.value == 1 RETURN x._key) " +
|
||||
"LET b = (FOR x IN " + c.name() + " FILTER x.value == 2 RETURN x._key) " +
|
||||
"LET c = (FOR x IN " + c.name() + " FILTER x.value == 3 RETURN x._key) " +
|
||||
"LET d = (FOR x IN " + c.name() + " FILTER x.value == 4 RETURN x._key) " +
|
||||
"LET e = (FOR x IN " + c.name() + " FILTER x.value == 5 RETURN x._key) " +
|
||||
"LET f = (FOR x IN " + c.name() + " FILTER x.value == 6 RETURN x._key) " +
|
||||
"LET g = (FOR x IN " + c.name() + " FILTER x.value == 7 RETURN x._key) " +
|
||||
"LET h = (FOR x IN " + c.name() + " FILTER x.value == 8 RETURN x._key) " +
|
||||
"LET i = (FOR x IN " + c.name() + " FILTER x.value == 9 RETURN x._key) " +
|
||||
"LET j = (FOR x IN " + c.name() + " FILTER x.value == 10 RETURN x._key) " +
|
||||
"RETURN [ a, b, c, d, e, f, g, h, i, j ]";
|
||||
|
||||
|
|
@ -1131,7 +1131,7 @@ function optimizerIndexesTestSuite () {
|
|||
|
||||
var results = AQL_EXECUTE(query);
|
||||
assertEqual(0, results.stats.scannedFull);
|
||||
assertNotEqual(0, results.stats.scannedIndex);
|
||||
assertNotEqual(0, results.stats.scannedIndex);
|
||||
assertEqual([ [ [ 'test1' ], [ 'test2' ], [ 'test3' ], [ 'test4' ], [ 'test5' ], [ 'test6' ], [ 'test7' ], [ 'test8' ], [ 'test9' ], [ 'test10' ] ] ], results.json);
|
||||
},
|
||||
|
||||
|
|
@ -1178,7 +1178,7 @@ function optimizerIndexesTestSuite () {
|
|||
|
||||
var results = AQL_EXECUTE(query);
|
||||
assertEqual(0, results.stats.scannedFull);
|
||||
assertNotEqual(0, results.stats.scannedIndex);
|
||||
assertNotEqual(0, results.stats.scannedIndex);
|
||||
assertEqual([ 'test0', 'test1', 'test2', 'test3', 'test4', 'test5', 'test6', 'test7', 'test8', 'test9' ], results.json);
|
||||
},
|
||||
|
||||
|
|
@ -1217,7 +1217,7 @@ function optimizerIndexesTestSuite () {
|
|||
|
||||
var results = AQL_EXECUTE(query);
|
||||
assertEqual(0, results.stats.scannedFull);
|
||||
assertNotEqual(0, results.stats.scannedIndex);
|
||||
assertNotEqual(0, results.stats.scannedIndex);
|
||||
assertEqual([ 'test0', 'test0', 'test1', 'test0', 'test1', 'test2', 'test0', 'test1', 'test2', 'test3' ], results.json);
|
||||
},
|
||||
|
||||
|
|
@ -1268,7 +1268,7 @@ function optimizerIndexesTestSuite () {
|
|||
|
||||
var results = AQL_EXECUTE(query);
|
||||
assertEqual(0, results.stats.scannedFull);
|
||||
assertNotEqual(0, results.stats.scannedIndex);
|
||||
assertNotEqual(0, results.stats.scannedIndex);
|
||||
assertEqual([ 'test0', 'test1', 'test2', 'test3' ], results.json);
|
||||
},
|
||||
|
||||
|
|
@ -1278,21 +1278,21 @@ function optimizerIndexesTestSuite () {
|
|||
|
||||
testSubqueryMadness : function () {
|
||||
c.ensureHashIndex("value"); // now we have a hash and a skiplist index
|
||||
var query = "LET a = (FOR x IN " + c.name() + " FILTER x.value == 1 FOR y IN " + c.name() + " FILTER y.value == x.value RETURN x._key) " +
|
||||
"LET b = (FOR x IN " + c.name() + " FILTER x.value == 2 FOR y IN " + c.name() + " FILTER y.value == x.value RETURN x._key) " +
|
||||
"LET c = (FOR x IN " + c.name() + " FILTER x.value == 3 FOR y IN " + c.name() + " FILTER y.value == x.value RETURN x._key) " +
|
||||
"LET d = (FOR x IN " + c.name() + " FILTER x.value == 4 FOR y IN " + c.name() + " FILTER y.value == x.value RETURN x._key) " +
|
||||
"LET e = (FOR x IN " + c.name() + " FILTER x.value == 5 FOR y IN " + c.name() + " FILTER y.value == x.value RETURN x._key) " +
|
||||
"LET f = (FOR x IN " + c.name() + " FILTER x.value == 6 FOR y IN " + c.name() + " FILTER y.value == x.value RETURN x._key) " +
|
||||
"LET g = (FOR x IN " + c.name() + " FILTER x.value == 7 FOR y IN " + c.name() + " FILTER y.value == x.value RETURN x._key) " +
|
||||
"LET h = (FOR x IN " + c.name() + " FILTER x.value == 8 FOR y IN " + c.name() + " FILTER y.value == x.value RETURN x._key) " +
|
||||
"LET i = (FOR x IN " + c.name() + " FILTER x.value == 9 FOR y IN " + c.name() + " FILTER y.value == x.value RETURN x._key) " +
|
||||
"LET j = (FOR x IN " + c.name() + " FILTER x.value == 10 FOR y IN " + c.name() + " FILTER y.value == x.value RETURN x._key) " +
|
||||
var query = "LET a = (FOR x IN " + c.name() + " FILTER x.value == 1 FOR y IN " + c.name() + " FILTER y.value == x.value RETURN x._key) " +
|
||||
"LET b = (FOR x IN " + c.name() + " FILTER x.value == 2 FOR y IN " + c.name() + " FILTER y.value == x.value RETURN x._key) " +
|
||||
"LET c = (FOR x IN " + c.name() + " FILTER x.value == 3 FOR y IN " + c.name() + " FILTER y.value == x.value RETURN x._key) " +
|
||||
"LET d = (FOR x IN " + c.name() + " FILTER x.value == 4 FOR y IN " + c.name() + " FILTER y.value == x.value RETURN x._key) " +
|
||||
"LET e = (FOR x IN " + c.name() + " FILTER x.value == 5 FOR y IN " + c.name() + " FILTER y.value == x.value RETURN x._key) " +
|
||||
"LET f = (FOR x IN " + c.name() + " FILTER x.value == 6 FOR y IN " + c.name() + " FILTER y.value == x.value RETURN x._key) " +
|
||||
"LET g = (FOR x IN " + c.name() + " FILTER x.value == 7 FOR y IN " + c.name() + " FILTER y.value == x.value RETURN x._key) " +
|
||||
"LET h = (FOR x IN " + c.name() + " FILTER x.value == 8 FOR y IN " + c.name() + " FILTER y.value == x.value RETURN x._key) " +
|
||||
"LET i = (FOR x IN " + c.name() + " FILTER x.value == 9 FOR y IN " + c.name() + " FILTER y.value == x.value RETURN x._key) " +
|
||||
"LET j = (FOR x IN " + c.name() + " FILTER x.value == 10 FOR y IN " + c.name() + " FILTER y.value == x.value RETURN x._key) " +
|
||||
"RETURN [ a, b, c, d, e, f, g, h, i, j ]";
|
||||
|
||||
var explain = AQL_EXPLAIN(query);
|
||||
var plan = explain.plan;
|
||||
|
||||
|
||||
var walker = function (nodes, func) {
|
||||
nodes.forEach(function(node) {
|
||||
if (node.type === "SubqueryNode") {
|
||||
|
|
@ -1303,7 +1303,7 @@ function optimizerIndexesTestSuite () {
|
|||
};
|
||||
|
||||
var indexNodes = 0, collectionNodes = 0;
|
||||
|
||||
|
||||
walker(plan.nodes, function (node) {
|
||||
if (node.type === "IndexNode") {
|
||||
++indexNodes;
|
||||
|
|
@ -1324,7 +1324,7 @@ function optimizerIndexesTestSuite () {
|
|||
|
||||
var results = AQL_EXECUTE(query);
|
||||
assertEqual(0, results.stats.scannedFull);
|
||||
assertNotEqual(0, results.stats.scannedIndex);
|
||||
assertNotEqual(0, results.stats.scannedIndex);
|
||||
assertEqual([ [ [ 'test1' ], [ 'test2' ], [ 'test3' ], [ 'test4' ], [ 'test5' ], [ 'test6' ], [ 'test7' ], [ 'test8' ], [ 'test9' ], [ 'test10' ] ] ], results.json);
|
||||
},
|
||||
|
||||
|
|
@ -1360,15 +1360,15 @@ function optimizerIndexesTestSuite () {
|
|||
[ "LET a = PASSTHRU('test35') FOR i IN " + c.name() + " FILTER i._key IN [ a ] RETURN i.value", [ 35 ] ],
|
||||
[ "FOR i IN " + c.name() + " FILTER i._key IN [ PASSTHRU('test35') ] RETURN i.value", [ 35 ] ],
|
||||
[ "LET a = PASSTHRU('test35') FOR i IN " + c.name() + " FILTER i._key IN [ a, a, a ] RETURN i.value", [ 35 ] ],
|
||||
[ "LET a = PASSTHRU('test35') FOR i IN " + c.name() + " FILTER i._key IN [ 'test35', 'test36' ] RETURN i.value", [ 35, 36 ] ],
|
||||
[ "LET a = PASSTHRU('test35'), b = PASSTHRU('test36'), c = PASSTHRU('test-9') FOR i IN " + c.name() + " FILTER i._key IN [ b, b, a, b, c ] RETURN i.value", [ 35, 36 ] ],
|
||||
[ "LET a = PASSTHRU('test35'), b = PASSTHRU('test36'), c = PASSTHRU('test37') FOR i IN " + c.name() + " FILTER i._key IN [ a, b, c ] RETURN i.value", [ 35, 36, 37 ] ],
|
||||
[ "LET a = PASSTHRU('test35'), b = PASSTHRU('test36'), c = PASSTHRU('test37') FOR i IN " + c.name() + " FILTER i._key IN [ a ] || i._key IN [ b, c ] RETURN i.value", [ 35, 36, 37 ] ],
|
||||
[ "LET a = PASSTHRU('test35'), b = PASSTHRU('test36'), c = PASSTHRU('test37'), d = PASSTHRU('test35') FOR i IN " + c.name() + " FILTER i._key IN [ a, b, c, d ] || i._key IN [ a, b, c, d ] RETURN i.value", [ 35, 36, 37 ] ],
|
||||
[ "LET a = PASSTHRU('test35') FOR i IN " + c.name() + " FILTER i._key IN [ 'test35', 'test36' ] RETURN i.value", [ 35, 36 ] ],
|
||||
[ "LET a = PASSTHRU('test35'), b = PASSTHRU('test36'), c = PASSTHRU('test-9') FOR i IN " + c.name() + " FILTER i._key IN [ b, b, a, b, c ] RETURN i.value", [ 35, 36 ] ],
|
||||
[ "LET a = PASSTHRU('test35'), b = PASSTHRU('test36'), c = PASSTHRU('test37') FOR i IN " + c.name() + " FILTER i._key IN [ a, b, c ] RETURN i.value", [ 35, 36, 37 ] ],
|
||||
[ "LET a = PASSTHRU('test35'), b = PASSTHRU('test36'), c = PASSTHRU('test37') FOR i IN " + c.name() + " FILTER i._key IN [ a ] || i._key IN [ b, c ] RETURN i.value", [ 35, 36, 37 ] ],
|
||||
[ "LET a = PASSTHRU('test35'), b = PASSTHRU('test36'), c = PASSTHRU('test37'), d = PASSTHRU('test35') FOR i IN " + c.name() + " FILTER i._key IN [ a, b, c, d ] || i._key IN [ a, b, c, d ] RETURN i.value", [ 35, 36, 37 ] ],
|
||||
[ "LET a = PASSTHRU('test35') FOR i IN " + c.name() + " FILTER i._key == a RETURN i.value", [ 35 ] ],
|
||||
[ "LET a = PASSTHRU('test35') FOR i IN " + c.name() + " FILTER i._key == a || i._key == a RETURN i.value", [ 35 ] ],
|
||||
[ "LET a = PASSTHRU('test35'), b = PASSTHRU('test36') FOR i IN " + c.name() + " FILTER i._key == a || i._key == b RETURN i.value", [ 35, 36 ] ],
|
||||
[ "LET a = PASSTHRU('test35'), b = PASSTHRU('test36'), c = PASSTHRU('test37'), d = PASSTHRU('test35') FOR i IN " + c.name() + " FILTER i._key == a || i._key == b || i._key == c || i._key == d RETURN i.value", [ 35, 36, 37 ] ]
|
||||
[ "LET a = PASSTHRU('test35'), b = PASSTHRU('test36') FOR i IN " + c.name() + " FILTER i._key == a || i._key == b RETURN i.value", [ 35, 36 ] ],
|
||||
[ "LET a = PASSTHRU('test35'), b = PASSTHRU('test36'), c = PASSTHRU('test37'), d = PASSTHRU('test35') FOR i IN " + c.name() + " FILTER i._key == a || i._key == b || i._key == c || i._key == d RETURN i.value", [ 35, 36, 37 ] ]
|
||||
];
|
||||
|
||||
queries.forEach(function(query) {
|
||||
|
|
@ -1384,7 +1384,7 @@ function optimizerIndexesTestSuite () {
|
|||
results.json.forEach(function(value) {
|
||||
assertNotEqual(-1, query[1].indexOf(value), query);
|
||||
});
|
||||
|
||||
|
||||
assertTrue(results.stats.scannedIndex < 10);
|
||||
assertEqual(0, results.stats.scannedFull);
|
||||
});
|
||||
|
|
@ -1419,7 +1419,7 @@ function optimizerIndexesTestSuite () {
|
|||
assertEqual(2, results.stats.scannedIndex);
|
||||
assertEqual(0, results.stats.scannedFull);
|
||||
},
|
||||
|
||||
|
||||
testIndexOrHashNoDocuments : function () {
|
||||
c.ensureHashIndex("value");
|
||||
var query = "FOR i IN " + c.name() + " FILTER i.value == 1 || i.value == 9 RETURN 1";
|
||||
|
|
@ -1580,7 +1580,7 @@ function optimizerIndexesTestSuite () {
|
|||
assertEqual(2, results.stats.scannedIndex);
|
||||
assertEqual(0, results.stats.scannedFull);
|
||||
},
|
||||
|
||||
|
||||
testIndexOrSkiplistNoDocuments : function () {
|
||||
var query = "FOR i IN " + c.name() + " FILTER i.value == 1 || i.value == 9 RETURN 1";
|
||||
|
||||
|
|
@ -1944,11 +1944,11 @@ function optimizerIndexesTestSuite () {
|
|||
assertEqual(0, results.stats.scannedFull);
|
||||
assertTrue(results.stats.scannedIndex > 0);
|
||||
},
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief test index usage
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
testIndexOrNoIndexBecauseOfDifferentAttributes : function () {
|
||||
AQL_EXECUTE("FOR i IN " + c.name() + " UPDATE i WITH { value2: i.value, value3: 1 } IN " + c.name());
|
||||
|
||||
|
|
@ -1973,7 +1973,7 @@ function optimizerIndexesTestSuite () {
|
|||
|
||||
assertEqual(-1, nodeTypes.indexOf("IndexNode"), query);
|
||||
var results = AQL_EXECUTE(query);
|
||||
assertEqual(2, results.json.length);
|
||||
assertEqual(2, results.json.length);
|
||||
assertTrue(results.stats.scannedFull > 0);
|
||||
assertEqual(0, results.stats.scannedIndex);
|
||||
});
|
||||
|
|
@ -2011,7 +2011,7 @@ function optimizerIndexesTestSuite () {
|
|||
|
||||
assertEqual(-1, nodeTypes.indexOf("IndexNode"), query);
|
||||
var results = AQL_EXECUTE(query);
|
||||
assertEqual(1, results.json.length, query);
|
||||
assertEqual(1, results.json.length, query);
|
||||
assertTrue(results.stats.scannedFull > 0);
|
||||
assertEqual(0, results.stats.scannedIndex);
|
||||
});
|
||||
|
|
@ -2067,7 +2067,7 @@ function optimizerIndexesTestSuite () {
|
|||
|
||||
assertNotEqual(-1, nodeTypes.indexOf("IndexNode"), query);
|
||||
var results = AQL_EXECUTE(query);
|
||||
assertEqual(1, results.json.length);
|
||||
assertEqual(1, results.json.length);
|
||||
assertTrue(results.stats.scannedIndex > 0);
|
||||
assertEqual(0, results.stats.scannedFull);
|
||||
});
|
||||
|
|
@ -2117,7 +2117,7 @@ function optimizerIndexesTestSuite () {
|
|||
|
||||
assertNotEqual(-1, nodeTypes.indexOf("IndexNode"), query);
|
||||
var results = AQL_EXECUTE(query);
|
||||
assertEqual(1, results.json.length);
|
||||
assertEqual(1, results.json.length);
|
||||
assertTrue(results.stats.scannedIndex > 0);
|
||||
assertEqual(0, results.stats.scannedFull);
|
||||
});
|
||||
|
|
@ -2143,7 +2143,7 @@ function optimizerIndexesTestSuite () {
|
|||
|
||||
assertNotEqual(-1, nodeTypes.indexOf("IndexNode"), query);
|
||||
var results = AQL_EXECUTE(query);
|
||||
assertEqual(1, results.json.length);
|
||||
assertEqual(1, results.json.length);
|
||||
assertTrue(results.stats.scannedIndex > 0);
|
||||
assertEqual(0, results.stats.scannedFull);
|
||||
});
|
||||
|
|
@ -2196,16 +2196,16 @@ function optimizerIndexesTestSuite () {
|
|||
|
||||
assertNotEqual(-1, nodeTypes.indexOf("IndexNode"), query);
|
||||
var results = AQL_EXECUTE(query);
|
||||
assertEqual(1, results.json.length);
|
||||
assertEqual(1, results.json.length);
|
||||
assertTrue(results.stats.scannedIndex > 0);
|
||||
assertEqual(0, results.stats.scannedFull);
|
||||
});
|
||||
},
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief test index usage
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
testIndexAndDespiteOr : function () {
|
||||
AQL_EXECUTE("FOR i IN " + c.name() + " UPDATE i WITH { value2: i.value, value3: 1 } IN " + c.name());
|
||||
|
||||
|
|
@ -2225,7 +2225,7 @@ function optimizerIndexesTestSuite () {
|
|||
|
||||
assertNotEqual(-1, nodeTypes.indexOf("IndexNode"), query);
|
||||
var results = AQL_EXECUTE(query);
|
||||
assertEqual(2, results.json.length, query);
|
||||
assertEqual(2, results.json.length, query);
|
||||
assertTrue(results.stats.scannedIndex > 0);
|
||||
assertEqual(0, results.stats.scannedFull);
|
||||
});
|
||||
|
|
@ -2273,7 +2273,7 @@ function optimizerIndexesTestSuite () {
|
|||
// The condition is impossible. We do not care for indexes.
|
||||
// assertNotEqual(-1, nodeTypes.indexOf("NoResultsNode"), query);
|
||||
var results = AQL_EXECUTE(query);
|
||||
assertEqual(0, results.json.length);
|
||||
assertEqual(0, results.json.length);
|
||||
assertTrue(results.stats.scannedIndex >= 0);
|
||||
assertEqual(0, results.stats.scannedFull);
|
||||
});
|
||||
|
|
@ -2312,7 +2312,7 @@ function optimizerIndexesTestSuite () {
|
|||
|
||||
assertEqual(-1, nodeTypes.indexOf("IndexNode"), query);
|
||||
var results = AQL_EXECUTE(query);
|
||||
assertEqual(2000, results.json.length);
|
||||
assertEqual(2000, results.json.length);
|
||||
assertEqual(0, results.stats.scannedIndex);
|
||||
assertTrue(results.stats.scannedFull > 0);
|
||||
});
|
||||
|
|
@ -2348,7 +2348,7 @@ function optimizerIndexesTestSuite () {
|
|||
|
||||
assertEqual(-1, nodeTypes.indexOf("IndexNode"), query);
|
||||
var results = AQL_EXECUTE(query);
|
||||
assertEqual(2000, results.json.length);
|
||||
assertEqual(2000, results.json.length);
|
||||
assertEqual(0, results.stats.scannedIndex);
|
||||
assertTrue(results.stats.scannedFull > 0);
|
||||
});
|
||||
|
|
@ -2372,7 +2372,7 @@ function optimizerIndexesTestSuite () {
|
|||
|
||||
assertEqual(-1, nodeTypes.indexOf("IndexNode"), query);
|
||||
var results = AQL_EXECUTE(query);
|
||||
assertEqual(2000, results.json.length);
|
||||
assertEqual(2000, results.json.length);
|
||||
assertEqual(0, results.stats.scannedIndex);
|
||||
assertTrue(results.stats.scannedFull > 0);
|
||||
});
|
||||
|
|
@ -2404,7 +2404,7 @@ function optimizerIndexesTestSuite () {
|
|||
|
||||
assertEqual(-1, nodeTypes.indexOf("IndexNode"), query);
|
||||
var results = AQL_EXECUTE(query);
|
||||
assertEqual(2000, results.json.length);
|
||||
assertEqual(2000, results.json.length);
|
||||
assertEqual(0, results.stats.scannedIndex);
|
||||
assertTrue(results.stats.scannedFull > 0);
|
||||
});
|
||||
|
|
@ -2437,7 +2437,7 @@ function optimizerIndexesTestSuite () {
|
|||
|
||||
assertNotEqual(-1, nodeTypes.indexOf("IndexNode"), query);
|
||||
var results = AQL_EXECUTE(query);
|
||||
assertEqual(1, results.json.length);
|
||||
assertEqual(1, results.json.length);
|
||||
assertEqual(2, results.json[0].value);
|
||||
assertTrue(results.stats.scannedIndex > 0);
|
||||
assertEqual(0, results.stats.scannedFull);
|
||||
|
|
@ -2474,7 +2474,7 @@ function optimizerIndexesTestSuite () {
|
|||
|
||||
assertNotEqual(-1, nodeTypes.indexOf("IndexNode"), query);
|
||||
var results = AQL_EXECUTE(query);
|
||||
assertEqual(1, results.json.length);
|
||||
assertEqual(1, results.json.length);
|
||||
assertEqual(2, results.json[0].value);
|
||||
assertTrue(results.stats.scannedIndex > 0);
|
||||
assertEqual(0, results.stats.scannedFull);
|
||||
|
|
@ -2511,7 +2511,7 @@ function optimizerIndexesTestSuite () {
|
|||
|
||||
assertNotEqual(-1, nodeTypes.indexOf("IndexNode"), query);
|
||||
var results = AQL_EXECUTE(query);
|
||||
assertEqual(1, results.json.length);
|
||||
assertEqual(1, results.json.length);
|
||||
assertEqual(2, results.json[0].value);
|
||||
assertTrue(results.stats.scannedIndex > 0);
|
||||
assertEqual(0, results.stats.scannedFull);
|
||||
|
|
@ -2551,7 +2551,7 @@ function optimizerIndexesTestSuite () {
|
|||
|
||||
assertNotEqual(-1, nodeTypes.indexOf("IndexNode"), query);
|
||||
var results = AQL_EXECUTE(query);
|
||||
assertEqual(1, results.json.length);
|
||||
assertEqual(1, results.json.length);
|
||||
assertEqual(2, results.json[0].value);
|
||||
assertTrue(results.stats.scannedIndex > 0);
|
||||
assertEqual(0, results.stats.scannedFull);
|
||||
|
|
@ -2588,7 +2588,7 @@ function optimizerIndexesTestSuite () {
|
|||
|
||||
assertNotEqual(-1, nodeTypes.indexOf("IndexNode"), query);
|
||||
var results = AQL_EXECUTE(query);
|
||||
assertEqual(1, results.json.length);
|
||||
assertEqual(1, results.json.length);
|
||||
assertEqual(2, results.json[0].value);
|
||||
assertTrue(results.stats.scannedIndex > 0);
|
||||
assertEqual(0, results.stats.scannedFull);
|
||||
|
|
@ -2617,7 +2617,7 @@ function optimizerIndexesTestSuite () {
|
|||
|
||||
assertEqual(-1, nodeTypes.indexOf("IndexNode"), query);
|
||||
var results = AQL_EXECUTE(query[0]);
|
||||
assertEqual(query[1], results.json.length);
|
||||
assertEqual(query[1], results.json.length);
|
||||
assertTrue(results.stats.scannedFull > 0);
|
||||
assertEqual(0, results.stats.scannedIndex);
|
||||
});
|
||||
|
|
@ -2651,7 +2651,7 @@ function optimizerIndexesTestSuite () {
|
|||
|
||||
assertNotEqual(-1, nodeTypes.indexOf("IndexNode"), query);
|
||||
var results = AQL_EXECUTE(query[0]);
|
||||
assertEqual(query[1], results.json.length);
|
||||
assertEqual(query[1], results.json.length);
|
||||
assertTrue(results.stats.scannedIndex > 0);
|
||||
assertEqual(0, results.stats.scannedFull);
|
||||
});
|
||||
|
|
@ -2664,7 +2664,7 @@ function optimizerIndexesTestSuite () {
|
|||
testIndexUsageIn : function () {
|
||||
c.ensureHashIndex("value2");
|
||||
c.ensureSkiplist("value3");
|
||||
|
||||
|
||||
AQL_EXECUTE("FOR i IN " + c.name() + " UPDATE i WITH { value2: i.value, value3: i.value } IN " + c.name());
|
||||
|
||||
var queries = [
|
||||
|
|
@ -2707,12 +2707,12 @@ function optimizerIndexesTestSuite () {
|
|||
[ "LET a = PASSTHRU({ ids: ['test23', 'test42'] }) FOR i IN " + c.name() + " FILTER i._key IN a.ids RETURN i._key", [ 'test23', 'test42' ] ],
|
||||
[ "LET a = PASSTHRU({ ids: [23, 42] }) FOR i IN " + c.name() + " FILTER i.value2 IN a.ids RETURN i.value2", [ 23, 42 ] ],
|
||||
[ "LET a = PASSTHRU({ ids: [23, 42] }) FOR i IN " + c.name() + " FILTER i.value3 IN a.ids RETURN i.value2", [ 23, 42 ] ],
|
||||
|
||||
|
||||
// non-arrays. should not fail but return no results
|
||||
[ "LET a = PASSTHRU({}) FOR i IN " + c.name() + " FILTER i._key IN a RETURN i._key", [ ] ],
|
||||
[ "LET a = PASSTHRU({}) FOR i IN " + c.name() + " FILTER i.value2 IN a RETURN i.value2", [ ] ],
|
||||
[ "LET a = PASSTHRU({}) FOR i IN " + c.name() + " FILTER i.value3 IN a RETURN i.value2", [ ] ]
|
||||
|
||||
|
||||
|
||||
|
||||
];
|
||||
|
|
@ -2725,7 +2725,7 @@ function optimizerIndexesTestSuite () {
|
|||
|
||||
assertNotEqual(-1, nodeTypes.indexOf("IndexNode"), query);
|
||||
var results = AQL_EXECUTE(query[0]);
|
||||
assertEqual(query[1].length, results.json.length, query);
|
||||
assertEqual(query[1].length, results.json.length, query);
|
||||
assertEqual(query[1].sort(), results.json.sort(), query);
|
||||
assertTrue(results.stats.scannedIndex >= 0);
|
||||
assertEqual(0, results.stats.scannedFull);
|
||||
|
|
@ -2739,7 +2739,7 @@ function optimizerIndexesTestSuite () {
|
|||
testIndexUsageInNoIndex : function () {
|
||||
c.ensureHashIndex("value2");
|
||||
c.ensureSkiplist("value3");
|
||||
|
||||
|
||||
AQL_EXECUTE("FOR i IN " + c.name() + " UPDATE i WITH { value2: i.value, value3: i.value } IN " + c.name());
|
||||
|
||||
var queries = [
|
||||
|
|
@ -2758,7 +2758,7 @@ function optimizerIndexesTestSuite () {
|
|||
assertNotEqual(-1, nodeTypes.indexOf("NoResultsNode"), query);
|
||||
|
||||
var results = AQL_EXECUTE(query[0]);
|
||||
assertEqual(0, results.json.length);
|
||||
assertEqual(0, results.json.length);
|
||||
assertEqual(0, results.stats.scannedIndex);
|
||||
assertEqual(0, results.stats.scannedFull);
|
||||
});
|
||||
|
|
@ -3525,7 +3525,7 @@ function optimizerIndexesMultiCollectionTestSuite () {
|
|||
db._drop("UnitTestsCollection2");
|
||||
c1 = db._create("UnitTestsCollection1");
|
||||
c2 = db._create("UnitTestsCollection2");
|
||||
|
||||
|
||||
var i;
|
||||
for (i = 0; i < 200; ++i) {
|
||||
c1.save({ _key: "test" + i, value: i });
|
||||
|
|
@ -3563,7 +3563,7 @@ function optimizerIndexesMultiCollectionTestSuite () {
|
|||
var subNodeTypes = plan.nodes[sub].subquery.nodes.map(function(node) {
|
||||
return node.type;
|
||||
});
|
||||
|
||||
|
||||
assertEqual("SingletonNode", subNodeTypes[0], query);
|
||||
var idx = subNodeTypes.indexOf("IndexNode");
|
||||
assertNotEqual(-1, idx, query); // index used for inner query
|
||||
|
|
@ -3594,7 +3594,7 @@ function optimizerIndexesMultiCollectionTestSuite () {
|
|||
var subNodeTypes = plan.nodes[sub].subquery.nodes.map(function(node) {
|
||||
return node.type;
|
||||
});
|
||||
|
||||
|
||||
assertEqual("SingletonNode", subNodeTypes[0], query);
|
||||
var idx = subNodeTypes.indexOf("IndexNode");
|
||||
assertNotEqual(-1, idx, query); // index used for inner query
|
||||
|
|
@ -3626,7 +3626,7 @@ function optimizerIndexesMultiCollectionTestSuite () {
|
|||
var subNodeTypes = plan.nodes[sub].subquery.nodes.map(function(node) {
|
||||
return node.type;
|
||||
});
|
||||
|
||||
|
||||
assertEqual("SingletonNode", subNodeTypes[0], query);
|
||||
var idx = subNodeTypes.indexOf("IndexNode");
|
||||
assertNotEqual(-1, idx, query); // index used for inner query
|
||||
|
|
@ -3658,7 +3658,7 @@ function optimizerIndexesMultiCollectionTestSuite () {
|
|||
var subNodeTypes = plan.nodes[sub].subquery.nodes.map(function(node) {
|
||||
return node.type;
|
||||
});
|
||||
|
||||
|
||||
assertEqual("SingletonNode", subNodeTypes[0], query);
|
||||
var idx = subNodeTypes.indexOf("IndexNode");
|
||||
assertNotEqual(-1, idx, query); // index used for inner query
|
||||
|
|
@ -3690,7 +3690,7 @@ function optimizerIndexesMultiCollectionTestSuite () {
|
|||
var subNodeTypes = plan.nodes[sub].subquery.nodes.map(function(node) {
|
||||
return node.type;
|
||||
});
|
||||
|
||||
|
||||
assertEqual("SingletonNode", subNodeTypes[0], query);
|
||||
var idx = subNodeTypes.indexOf("IndexNode");
|
||||
assertNotEqual(-1, idx, query); // index used for inner query
|
||||
|
|
@ -3722,13 +3722,105 @@ function optimizerIndexesMultiCollectionTestSuite () {
|
|||
var subNodeTypes = plan.nodes[sub].subquery.nodes.map(function(node) {
|
||||
return node.type;
|
||||
});
|
||||
|
||||
|
||||
assertEqual("SingletonNode", subNodeTypes[0], query);
|
||||
var idx = subNodeTypes.indexOf("IndexNode");
|
||||
assertNotEqual(-1, idx, query); // index used for inner query
|
||||
assertEqual("skiplist", plan.nodes[sub].subquery.nodes[idx].indexes[0].type);
|
||||
assertEqual(-1, subNodeTypes.indexOf("SortNode"), query); // must not have sort node for inner query
|
||||
}
|
||||
},
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief test index usage
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
testPreventMoveFilterPastModify1 : function () {
|
||||
c1.ensureIndex({ type: "hash", fields: [ "value" ] });
|
||||
c2.ensureIndex({ type: "hash", fields: [ "value" ] });
|
||||
c2.ensureIndex({ type: "skiplist", fields: [ "ref" ] });
|
||||
var query = `
|
||||
FOR i IN ${c1.name()}
|
||||
FOR j IN ${c2.name()}
|
||||
UPDATE j WITH { tick: i } in ${c2.name()}
|
||||
FILTER i.value == 1
|
||||
RETURN [i, NEW]
|
||||
`;
|
||||
|
||||
var plan = AQL_EXPLAIN(query).plan;
|
||||
var nodeTypes = plan.nodes.map(function(node) {
|
||||
return node.type;
|
||||
});
|
||||
|
||||
assertEqual("SingletonNode", nodeTypes[0], query);
|
||||
assertEqual(-1, nodeTypes.indexOf("IndexNode"), query); // no index
|
||||
assertNotEqual(-1, nodeTypes.indexOf("FilterNode"), query); // post filter
|
||||
},
|
||||
|
||||
testPreventMoveFilterPastModify2 : function () {
|
||||
c1.ensureIndex({ type: "hash", fields: [ "value" ] });
|
||||
c2.ensureIndex({ type: "hash", fields: [ "value" ] });
|
||||
c2.ensureIndex({ type: "skiplist", fields: [ "ref" ] });
|
||||
var query = `
|
||||
FOR i IN ${c1.name()}
|
||||
FOR j IN ${c2.name()}
|
||||
UPDATE j WITH { tick: i } in ${c2.name()}
|
||||
FILTER j.value == 1
|
||||
RETURN [i, NEW]
|
||||
`;
|
||||
|
||||
var plan = AQL_EXPLAIN(query).plan;
|
||||
var nodeTypes = plan.nodes.map(function(node) {
|
||||
return node.type;
|
||||
});
|
||||
|
||||
assertEqual("SingletonNode", nodeTypes[0], query);
|
||||
assertEqual(-1, nodeTypes.indexOf("IndexNode"), query); // no index
|
||||
assertNotEqual(-1, nodeTypes.indexOf("FilterNode"), query); // post filter
|
||||
},
|
||||
|
||||
testPreventMoveSortPastModify1 : function () {
|
||||
c1.ensureIndex({ type: "hash", fields: [ "value" ] });
|
||||
c2.ensureIndex({ type: "hash", fields: [ "value" ] });
|
||||
c2.ensureIndex({ type: "skiplist", fields: [ "ref" ] });
|
||||
var query = `
|
||||
FOR i IN ${c1.name()}
|
||||
FOR j IN ${c2.name()}
|
||||
UPDATE j WITH { tick: i } in ${c2.name()}
|
||||
SORT i.value
|
||||
RETURN [i, NEW]
|
||||
`;
|
||||
|
||||
var plan = AQL_EXPLAIN(query).plan;
|
||||
var nodeTypes = plan.nodes.map(function(node) {
|
||||
return node.type;
|
||||
});
|
||||
|
||||
assertEqual("SingletonNode", nodeTypes[0], query);
|
||||
assertEqual(-1, nodeTypes.indexOf("IndexNode"), query); // no index
|
||||
assertNotEqual(-1, nodeTypes.indexOf("SortNode"), query); // post filter
|
||||
},
|
||||
|
||||
testPreventMoveSortPastModify2 : function () {
|
||||
c1.ensureIndex({ type: "hash", fields: [ "value" ] });
|
||||
c2.ensureIndex({ type: "hash", fields: [ "value" ] });
|
||||
c2.ensureIndex({ type: "skiplist", fields: [ "ref" ] });
|
||||
var query = `
|
||||
FOR i IN ${c1.name()}
|
||||
FOR j IN ${c2.name()}
|
||||
UPDATE j WITH { tick: i } in ${c2.name()}
|
||||
SORT NEW.value
|
||||
RETURN [i, NEW]
|
||||
`;
|
||||
|
||||
var plan = AQL_EXPLAIN(query).plan;
|
||||
var nodeTypes = plan.nodes.map(function(node) {
|
||||
return node.type;
|
||||
});
|
||||
|
||||
assertEqual("SingletonNode", nodeTypes[0], query);
|
||||
assertEqual(-1, nodeTypes.indexOf("IndexNode"), query); // no index
|
||||
assertNotEqual(-1, nodeTypes.indexOf("SortNode"), query); // post filter
|
||||
},
|
||||
|
||||
};
|
||||
}
|
||||
|
|
@ -3741,4 +3833,3 @@ jsunity.run(optimizerIndexesTestSuite);
|
|||
jsunity.run(optimizerIndexesMultiCollectionTestSuite);
|
||||
|
||||
return jsunity.done();
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue