8000 Bug fix/search 238 late materialization with constrained heap (#14722) · arangodb/arangodb@73bf4d3 · GitHub
[go: up one dir, main page]

Skip to content

Commit 73bf4d3

Browse files
authored
Bug fix/search 238 late materialization with constrained heap (#14722)
* add test for view case * find a better place for sort * fix formatting * add index case test * moar tests * temporary relaxed assertion
1 parent b81d313 commit 73bf4d3

5 files changed

+92
-3
lines changed

CHANGELOG

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
devel
22
-----
3+
* SEARCH-238: Improved SortNodes placement optimization in cluster so
4+
late materialization could cover more cases
35

46
* Fix internal iterator states after intermediate commits in write
57
transactions. Iterators could point to invalid data after an

arangod/Aql/OptimizerRules.cpp

Lines changed: 26 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4633,6 +4633,7 @@ void arangodb::aql::distributeSortToClusterRule(Optimizer* opt,
46334633
OptimizerRule const& rule) {
46344634
::arangodb::containers::SmallVector<ExecutionNode*>::allocator_type::arena_type a;
46354635
::arangodb::containers::SmallVector<ExecutionNode*> nodes{a};
4636+
VarSet usedBySort;
46364637
plan->findNodesOfType(nodes, EN::GATHER, true);
46374638

46384639
bool modified = false;
@@ -4694,14 +4695,37 @@ void arangodb::aql::distributeSortToClusterRule(Optimizer* opt,
46944695

46954696
case EN::SORT: {
46964697
auto thisSortNode = ExecutionNode::castTo<SortNode*>(inspectNode);
4697-
4698+
usedBySort.clear();
4699+
thisSortNode->getVariablesUsedHere(usedBySort);
46984700
// remember our cursor...
46994701
parents = inspectNode->getParents();
47004702
// then unlink the filter/calculator from the plan
47014703
plan->unlinkNode(inspectNode);
47024704
// and re-insert into plan in front of the remoteNode
47034705
if (thisSortNode->_reinsertInCluster) {
4704-
plan->insertDependency(rn, inspectNode);
4706+
// let's look for the best place for that SORT.
4707+
// We could skip over several calculations if
4708+
// they are not needed for our sort. So we could calculate
4709+
// more lazily and even make late materialization possible
4710+
ExecutionNode* insertPoint = rn;
4711+
auto current = insertPoint->getFirstDependency();
4712+
while (current != nullptr &&
4713+
current->getType() == EN::CALCULATION) {
4714+
auto nn = ExecutionNode::castTo<CalculationNode*>(current);
4715+
if (!nn->expression()->isDeterministic()) {
4716+
// let's not touch non-deterministic calculation
4717+
// as results may depend on calls count and sort could change this
4718+
break;
4719+
}
4720+
auto variable = nn->outVariable();
4721+
if (usedBySort.find(variable) == usedBySort.end()) {
4722+
insertPoint = current;
4723+
} else {
4724+
break; // first node used by sort. We should stop here.
4725+
}
4726+
current = current->getFirstDependency();
4727+
}
4728+
plan->insertDependency(insertPoint, inspectNode);
47054729
}
47064730

47074731
gatherNode->elements(thisSortNode->elements());

tests/js/server/aql/aql-optimizer-rule-late-document-materialization-arangosearch.inc

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -380,6 +380,34 @@
380380
});
381381
assertEqual(0, expected.size);
382382
},
383+
testConstrainedSortOnDbServer() {
384+
let query = "FOR d IN " + vn + " SEARCH d.value > 9 SORT BM25(d) LIMIT 10 RETURN {key: d._key, value: d.value}";
385+
let plan = AQL_EXPLAIN(query).plan;
386+
assertNotEqual(-1, plan.rules.indexOf(ruleName));
387+
let materializeNodeFound = false;
388+
let nodeDependency = null;
389+
plan.nodes.forEach(function(node) {
390+
if( node.type === "MaterializeNode") {
391+
assertFalse(materializeNodeFound);
392+
// FIXME: temporary relaxed assertion
393+
// We need to fix node placement in oneshard mode
394+
// first. And than we indeed will get expected node placement
395+
// assertEqual(nodeDependency.type, isCluster ? "SortNode" : "LimitNode");
396+
assertTrue(nodeDependency.type === "SortNode" || nodeDependency.type === "LimitNode");
397+
materializeNodeFound = true;
398+
}
399+
nodeDependency = node;
400+
});
401+
assertTrue(materializeNodeFound);
402+
let result = AQL_EXECUTE(query);
403+
assertEqual(4, result.json.length);
404+
let expected = new Set(['c_0', 'c_1', 'c_2', 'c_3']);
405+
result.json.forEach(function(doc) {
406+
assertTrue(expected.has(doc.key));
407+
expected.delete(doc.key);
408+
});
409+
assertEqual(0, expected.size);
410+
}
383411
};
384412
};
385413
}());

tests/js/server/aql/aql-optimizer-rule-late-document-materialization.js

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -607,6 +607,31 @@ function lateDocumentMaterializationRuleTestSuite () {
607607
let result = AQL_EXECUTE(query);
608608
assertEqual(1, result.json.length);
609609
assertEqual(result.json[0]._key, 'c0');
610+
},
611+
test A36C ConstrainedSortOnDbServer() {
612+
let query = "FOR d IN " + prefixIndexCollectionName + " FILTER d.obj.b == {sb: 'b_val_0'} " +
613+
"SORT d.obj.b LIMIT 10 RETURN {key: d._key, value: d.some_value_from_doc}";
614+
let plan = AQL_EXPLAIN(query).plan;
615+
assertNotEqual(-1, plan.rules.indexOf(ruleName));
616+
let materializeNodeFound = false;
617+
let nodeDependency = null;
618+
plan.nodes.forEach(function(node) {
619+
if( node.type === "MaterializeNode") {
620+
assertFalse(materializeNodeFound);
621+
assertEqual(nodeDependency.type, isCluster ? "SortNode" : "LimitNode");
622+
materializeNodeFound = true;
623+
}
624+
nodeDependency = node;
625+
});
626+
assertTrue(materializeNodeFound);
627+
let result = AQL_EXECUTE(query);
628+
assertEqual(1, result.json.length);
629+
let expected = new Set(['c0']);
630+
result.json.forEach(function(doc) {
631+
assertTrue(expected.has(doc.key));
632+
expected.delete(doc.key);
633+
});
634+
assertEqual(0, expected.size);
610635
}
611636
};
612637
}

tests/js/server/aql/aql-queries-optimizer-limit-cluster.js

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -601,7 +601,17 @@ function ahuacatlQueryOptimizerLimitTestSuite () {
601601
var actual = getQueryResults(query);
602602
assertEqual(0, actual.length);
603603

604-
assertEqual([ "SingletonNode", "EnumerateCollectionNode", "CalculationNode", "CalculationNode", "SortNode", "RemoteNode", "GatherNode", "LimitNode", "FilterNode", "ReturnNode" ], explain(query));
604+
assertEqual([ "SingletonNode", "EnumerateCollectionNode", "CalculationNode", "SortNode", "CalculationNode",
605+
"RemoteNode", "GatherNode", "LimitNode", "FilterNode", "ReturnNode" ], explain(query));
606+
},
607+
testLimitFullCollectionSort3_DoubleCalculation : function () {
608+
var query = "FOR c IN " + cn + " SORT c.value LIMIT 0, 10 FILTER c.value >= 20 && c.value < 30 RETURN c.value2";
609+
610+
var actual = getQueryResults(query);
611+
assertEqual(0, actual.length);
612+
613+
assertEqual([ "SingletonNode", "EnumerateCollectionNode", "CalculationNode", "SortNode", "CalculationNode",
614+
"CalculationNode", "RemoteNode", "GatherNode", "LimitNode", "FilterNode", "ReturnNode" ], explain(query));
605615
},
606616

607617
////////////////////////////////////////////////////////////////////////////////

0 commit comments

Comments
 (0)
0