1
0
Fork 0

Reduce planning time of high depth Traversals (#3942)

* Improved the cost estimation of traversals to be independent from max search depth. This fixes #3917

* fix failing test on MSVC
This commit is contained in:
Michael Hackstein 2017-12-08 15:45:08 +01:00 committed by Jan
parent a7b4599ff9
commit 613cc4f749
4 changed files with 94 additions and 2 deletions

View File

@ -1,6 +1,9 @@
devel
-----
* fixed issue #3917: traversals with high maximal depth take extremely long
in planning phase.
* UI: fixed issue #3822: disabled name input field for system collections
* fixed issue #3741: fix terminal color output in Windows

View File

@ -61,6 +61,14 @@ static uint64_t checkTraversalDepthValue(AstNode const* node) {
"invalid traversal depth");
}
double v = node->getDoubleValue();
if (v > static_cast<double>(INT64_MAX)) {
// we cannot safely represent this value in an int64_t.
// which is already far bigger than we will ever traverse, so
// we can safely abort here and not care about uint64_t.
THROW_ARANGO_EXCEPTION_MESSAGE(TRI_ERROR_QUERY_PARSE,
"invalid traversal depth");
}
double intpart;
if (modf(v, &intpart) != 0.0 || v < 0.0) {
THROW_ARANGO_EXCEPTION_MESSAGE(TRI_ERROR_QUERY_PARSE,

View File

@ -532,7 +532,7 @@ double TraverserOptions::estimateCost(size_t& nrItems) const {
size_t baseCreateItems = 0;
double baseCost = costForLookupInfoList(_baseLookupInfos, baseCreateItems);
for (uint64_t depth = 0; depth < maxDepth; ++depth) {
for (uint64_t depth = 0; depth < maxDepth && depth < 10; ++depth) {
auto liList = _depthLookupInfo.find(depth);
if (liList == _depthLookupInfo.end()) {
// No LookupInfo for this depth use base
@ -545,6 +545,12 @@ double TraverserOptions::estimateCost(size_t& nrItems) const {
count *= createItems;
}
}
if (maxDepth > 10) {
// We have a too high depth this cost will be pruned anyway
cost *= (maxDepth - 10) * 10;
count *= (maxDepth - 10) * 10;
}
nrItems = count;
return cost;
}

View File

@ -1644,7 +1644,82 @@ function complexInternaSuite () {
let res = db._query(query);
assertEqual(res.count(), 1);
assertEqual(res.toArray(), [vertex.B]);
}
},
testLargeMaxDepth: function () {
let query = `
WITH ${vn}
FOR v, e, p IN 1..4294967295 OUTBOUND "${vn}/A" ${en}
FILTER p.edges[1]._id != "${edge.BC}"
FILTER p.vertices[2]._id != "${vertex.C}"
RETURN v._id`;
let res = db._query(query);
assertEqual(res.count(), 1);
assertEqual(res.toArray(), [vertex.B]);
},
testInt64MaxMaxDepth: function () {
let query = `
WITH ${vn}
FOR v, e, p IN 1..9223372036854775807 OUTBOUND "${vn}/A" ${en}
FILTER p.edges[1]._id != "${edge.BC}"
FILTER p.vertices[2]._id != "${vertex.C}"
RETURN v._id`;
let res = db._query(query);
assertEqual(res.count(), 1);
assertEqual(res.toArray(), [vertex.B]);
},
testEvenLargerMaxDepth: function () {
let query = `
WITH ${vn}
FOR v, e, p IN 1..18446744073709551615 OUTBOUND "${vn}/A" ${en}
FILTER p.edges[1]._id != "${edge.BC}"
FILTER p.vertices[2]._id != "${vertex.C}"
RETURN v._id`;
try {
db._query(query);
fail();
} catch (e) {
assertEqual(e.errorNum, errors.ERROR_QUERY_PARSE.code);
}
},
testNegativeMinDepth: function () {
let query = `
WITH ${vn}
FOR v, e, p IN -1..3 OUTBOUND "${vn}/A" ${en}
FILTER p.edges[1]._id != "${edge.BC}"
FILTER p.vertices[2]._id != "${vertex.C}"
RETURN v._id`;
try {
db._query(query);
fail();
} catch (e) {
assertEqual(e.errorNum, errors.ERROR_QUERY_PARSE.code);
}
},
testNegativeMaxDepth: function () {
let query = `
WITH ${vn}
FOR v, e, p IN 1..-3 OUTBOUND "${vn}/A" ${en}
FILTER p.edges[1]._id != "${edge.BC}"
FILTER p.vertices[2]._id != "${vertex.C}"
RETURN v._id`;
try {
db._query(query);
fail();
} catch (e) {
assertEqual(e.errorNum, errors.ERROR_QUERY_PARSE.code);
}
},
};
}