From 76f84f2c6c7672d7d58173ac35b72b8d55e9d5c9 Mon Sep 17 00:00:00 2001 From: Jan Date: Tue, 26 Nov 2019 10:44:45 +0100 Subject: [PATCH] Allow the optimizer to use indexes (#10543) * Allow the optimizer to use indexes when a collection attribute is compared to anexpansion followed by an attribute name, e.g. `doc.value IN something[*].name`. * Update CHANGELOG --- CHANGELOG | 4 +++ arangod/Indexes/Index.cpp | 3 +- tests/js/server/aql/aql-optimizer-indexes.js | 34 ++++++++++++++++++++ 3 files changed, 39 insertions(+), 2 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index 5fa8c29199..26b3ac0444 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,6 +1,10 @@ v3.5.3 (XXXX-XX-XX) ------------------- +* Allow the optimizer to use indexes when a collection attribute is compared to + an expansion followed by an attribute name, e.g. + `doc.value IN something[*].name`. + * Updated arangosync to 0.7.0. * Fixed issue #10470: The WebUI now shows potential errors and details which diff --git a/arangod/Indexes/Index.cpp b/arangod/Indexes/Index.cpp index 2831d6431f..636755e804 100644 --- a/arangod/Indexes/Index.cpp +++ b/arangod/Indexes/Index.cpp @@ -825,8 +825,7 @@ bool Index::canUseConditionPart(arangodb::aql::AstNode const* access, other->type == arangodb::aql::NODE_TYPE_ATTRIBUTE_ACCESS)) { // value IN a.b OR value IN a.b[*] arangodb::aql::Ast::getReferencedVariables(access, variables); - if (other->type == arangodb::aql::NODE_TYPE_ATTRIBUTE_ACCESS && - variables.find(reference) != variables.end()) { + if (variables.find(reference) != variables.end()) { variables.clear(); arangodb::aql::Ast::getReferencedVariables(other, variables); } diff --git a/tests/js/server/aql/aql-optimizer-indexes.js b/tests/js/server/aql/aql-optimizer-indexes.js index 44c37fe706..eeed785ae5 100644 --- a/tests/js/server/aql/aql-optimizer-indexes.js +++ b/tests/js/server/aql/aql-optimizer-indexes.js @@ -56,6 +56,40 @@ function optimizerIndexesTestSuite () { db._drop("UnitTestsCollection"); }, + testIndexUsedForExpansion1 : function () { + let query = "LET test = NOOPT([{ value: 1 }, { value : 2 }]) FOR doc IN " + c.name() + " FILTER doc.value IN test[*].value SORT doc.value RETURN doc.value"; + + let plan = AQL_EXPLAIN(query).plan; + let nodeTypes = plan.nodes.map(function(node) { + return node.type; + }); + + assertEqual("SingletonNode", nodeTypes[0], query); + assertNotEqual(-1, nodeTypes.indexOf("IndexNode"), query); + + let results = AQL_EXECUTE(query); + assertEqual([ 1, 2 ], results.json, query); + assertEqual(0, results.stats.scannedFull); + assertTrue(results.stats.scannedIndex > 0); + }, + + testIndexUsedForExpansion2 : function () { + let query = "LET test = NOOPT([1, 2]) FOR doc IN " + c.name() + " FILTER doc.value IN test[*] SORT doc.value RETURN doc.value"; + + let plan = AQL_EXPLAIN(query).plan; + let nodeTypes = plan.nodes.map(function(node) { + return node.type; + }); + + assertEqual("SingletonNode", nodeTypes[0], query); + assertNotEqual(-1, nodeTypes.indexOf("IndexNode"), query); + + let results = AQL_EXECUTE(query); + assertEqual([ 1, 2 ], results.json, query); + assertEqual(0, results.stats.scannedFull); + assertTrue(results.stats.scannedIndex > 0); + }, + testMultiIndexesOrCondition : function () { let values = [ [ "abc", true, true ],