mirror of https://gitee.com/bigwinds/arangodb
parent
bea5cd0e26
commit
544f7d4ab4
11
CHANGELOG
11
CHANGELOG
|
@ -5,6 +5,12 @@ v2.3.1 (2014-11-28)
|
|||
|
||||
* fixed issue #1126
|
||||
|
||||
* fixed non-working subquery index optimizations
|
||||
|
||||
* do not restrict summary of Foxx applications to 60 characters
|
||||
|
||||
* fixed display of "required" path parameters in Foxx application documentation
|
||||
|
||||
* added more optimizations of constants values in AQL FILTER conditions
|
||||
|
||||
* fixed invalid or-to-in optimization for FILTERs containing comparisons
|
||||
|
@ -19,9 +25,8 @@ v2.3.1 (2014-11-28)
|
|||
|
||||
* fixed AQL optimizer cost estimation for LIMIT node
|
||||
|
||||
|
||||
v2.3.0 (2014-11-18)
|
||||
-------------------
|
||||
* prevent Foxx queues from permanently writing to the journal even when
|
||||
server is idle
|
||||
|
||||
|
||||
v2.3.0 (2014-11-18)
|
||||
|
|
|
@ -556,6 +556,7 @@ SHELL_SERVER_AQL = @top_srcdir@/js/server/tests/aql-arithmetic.js \
|
|||
@top_srcdir@/js/server/tests/aql-operators.js \
|
||||
@top_srcdir@/js/server/tests/aql-optimizer-dynamic-bounds.js \
|
||||
@top_srcdir@/js/server/tests/aql-optimizer-filters.js \
|
||||
@top_srcdir@/js/server/tests/aql-optimizer-indexes.js \
|
||||
@top_srcdir@/js/server/tests/aql-optimizer-rule-interchange-adjacent-enumerations-noncluster.js \
|
||||
@top_srcdir@/js/server/tests/aql-optimizer-rule-move-calculations-up.js \
|
||||
@top_srcdir@/js/server/tests/aql-optimizer-rule-move-filters-up.js \
|
||||
|
|
|
@ -1019,12 +1019,28 @@ void ExecutionPlan::checkLinkage () {
|
|||
struct VarUsageFinder : public WalkerWorker<ExecutionNode> {
|
||||
std::unordered_set<Variable const*> _usedLater;
|
||||
std::unordered_set<Variable const*> _valid;
|
||||
std::unordered_map<VariableId, ExecutionNode*> _varSetBy;
|
||||
std::unordered_map<VariableId, ExecutionNode*>* _varSetBy;
|
||||
bool const _ownsVarSetBy;
|
||||
|
||||
VarUsageFinder () {
|
||||
VarUsageFinder ()
|
||||
: _varSetBy(new std::unordered_map<VariableId, ExecutionNode*>()),
|
||||
_ownsVarSetBy(true) {
|
||||
|
||||
TRI_ASSERT(_varSetBy != nullptr);
|
||||
}
|
||||
|
||||
|
||||
explicit VarUsageFinder (std::unordered_map<VariableId, ExecutionNode*>* varSetBy)
|
||||
: _varSetBy(varSetBy),
|
||||
_ownsVarSetBy(false) {
|
||||
|
||||
TRI_ASSERT(_varSetBy != nullptr);
|
||||
}
|
||||
|
||||
~VarUsageFinder () {
|
||||
if (_ownsVarSetBy) {
|
||||
TRI_ASSERT(_varSetBy != nullptr);
|
||||
delete _varSetBy;
|
||||
}
|
||||
}
|
||||
|
||||
bool before (ExecutionNode* en) override final {
|
||||
|
@ -1043,14 +1059,14 @@ struct VarUsageFinder : public WalkerWorker<ExecutionNode> {
|
|||
auto&& setHere = en->getVariablesSetHere();
|
||||
for (auto v : setHere) {
|
||||
_valid.insert(v);
|
||||
_varSetBy.emplace(std::make_pair(v->id, en));
|
||||
_varSetBy->emplace(std::make_pair(v->id, en));
|
||||
}
|
||||
en->setVarsValid(_valid);
|
||||
en->setVarUsageValid();
|
||||
}
|
||||
|
||||
bool enterSubquery (ExecutionNode*, ExecutionNode* sub) override final {
|
||||
VarUsageFinder subfinder;
|
||||
VarUsageFinder subfinder(_varSetBy);
|
||||
subfinder._valid = _valid; // need a copy for the subquery!
|
||||
sub->walk(&subfinder);
|
||||
|
||||
|
@ -1066,7 +1082,7 @@ struct VarUsageFinder : public WalkerWorker<ExecutionNode> {
|
|||
void ExecutionPlan::findVarUsage () {
|
||||
::VarUsageFinder finder;
|
||||
root()->walk(&finder);
|
||||
_varSetBy = finder._varSetBy;
|
||||
_varSetBy = *finder._varSetBy;
|
||||
_varUsageComputed = true;
|
||||
}
|
||||
|
||||
|
|
|
@ -916,7 +916,7 @@ class FilterToEnumCollFinder : public WalkerWorker<ExecutionNode> {
|
|||
|
||||
bool valid = true; // are all the range infos valid?
|
||||
|
||||
for(auto x: *map) {
|
||||
for (auto x: *map) {
|
||||
valid &= x.second.isValid();
|
||||
if (! valid) {
|
||||
break;
|
||||
|
@ -1074,6 +1074,7 @@ class FilterToEnumCollFinder : public WalkerWorker<ExecutionNode> {
|
|||
void buildRangeInfo (AstNode const* node,
|
||||
Variable const*& enumCollVar,
|
||||
std::string& attr) {
|
||||
|
||||
if (node->type == NODE_TYPE_REFERENCE) {
|
||||
auto x = static_cast<Variable*>(node->getData());
|
||||
auto setter = _plan->getVarSetBy(x->id);
|
||||
|
@ -1098,6 +1099,7 @@ class FilterToEnumCollFinder : public WalkerWorker<ExecutionNode> {
|
|||
if (node->type == NODE_TYPE_OPERATOR_BINARY_EQ) {
|
||||
auto lhs = node->getMember(0);
|
||||
auto rhs = node->getMember(1);
|
||||
|
||||
if (rhs->type == NODE_TYPE_ATTRIBUTE_ACCESS) {
|
||||
buildRangeInfo(rhs, enumCollVar, attr);
|
||||
if (enumCollVar != nullptr) {
|
||||
|
|
|
@ -0,0 +1,151 @@
|
|||
/*jshint strict: false, maxlen: 500 */
|
||||
/*global require, assertEqual, assertNotEqual, AQL_EXPLAIN, AQL_EXECUTE */
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief tests for index usage
|
||||
///
|
||||
/// @file
|
||||
///
|
||||
/// DISCLAIMER
|
||||
///
|
||||
/// Copyright 2010-2012 triagens GmbH, Cologne, Germany
|
||||
///
|
||||
/// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
/// you may not use this file except in compliance with the License.
|
||||
/// You may obtain a copy of the License at
|
||||
///
|
||||
/// http://www.apache.org/licenses/LICENSE-2.0
|
||||
///
|
||||
/// Unless required by applicable law or agreed to in writing, software
|
||||
/// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
/// See the License for the specific language governing permissions and
|
||||
/// limitations under the License.
|
||||
///
|
||||
/// Copyright holder is triAGENS GmbH, Cologne, Germany
|
||||
///
|
||||
/// @author Jan Steemann
|
||||
/// @author Copyright 2012, triAGENS GmbH, Cologne, Germany
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
var jsunity = require("jsunity");
|
||||
var db = require("org/arangodb").db;
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief test suite
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
function optimizerIndexesTestSuite () {
|
||||
var c;
|
||||
|
||||
return {
|
||||
setUp : function () {
|
||||
db._drop("UnitTestsCollection");
|
||||
c = db._create("UnitTestsCollection");
|
||||
|
||||
for (var i = 0; i < 2000; ++i) {
|
||||
c.save({ value: i });
|
||||
}
|
||||
|
||||
c.ensureSkiplist("value");
|
||||
},
|
||||
|
||||
tearDown : function () {
|
||||
db._drop("UnitTestsCollection");
|
||||
},
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief test index usage
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
testUseIndexSimple : function () {
|
||||
var query = "FOR i IN " + c.name() + " FILTER i.value >= 10 SORT i.value LIMIT 10 RETURN i.value";
|
||||
|
||||
var plan = AQL_EXPLAIN(query).plan;
|
||||
var nodeTypes = plan.nodes.map(function(node) {
|
||||
return node.type;
|
||||
});
|
||||
|
||||
assertEqual("SingletonNode", nodeTypes[0], query);
|
||||
assertNotEqual(-1, nodeTypes.indexOf("IndexRangeNode"), query);
|
||||
assertEqual(-1, nodeTypes.indexOf("SortNode"), query);
|
||||
assertEqual("ReturnNode", nodeTypes[nodeTypes.length - 1], query);
|
||||
|
||||
var results = AQL_EXECUTE(query);
|
||||
assertEqual([ 10, 11, 12, 13, 14, 15, 16, 17, 18, 19 ], results.json, query);
|
||||
assertEqual(0, results.stats.scannedFull);
|
||||
assertTrue(results.stats.scannedIndex > 0);
|
||||
},
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief test index usage
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
testUseIndexSubquery : function () {
|
||||
var query = "LET results = (FOR i IN " + c.name() + " FILTER i.value >= 10 SORT i.value LIMIT 10 RETURN i.value) RETURN results";
|
||||
|
||||
var plan = AQL_EXPLAIN(query).plan;
|
||||
var nodeTypes = plan.nodes.map(function(node) {
|
||||
return node.type;
|
||||
});
|
||||
|
||||
assertEqual("SingletonNode", nodeTypes[0], query);
|
||||
assertEqual("SubqueryNode", nodeTypes[1], query);
|
||||
|
||||
var subNodeTypes = plan.nodes[1].subquery.nodes.map(function(node) {
|
||||
return node.type;
|
||||
});
|
||||
assertNotEqual(-1, subNodeTypes.indexOf("IndexRangeNode"), query);
|
||||
assertEqual(-1, subNodeTypes.indexOf("SortNode"), query);
|
||||
assertEqual("ReturnNode", nodeTypes[nodeTypes.length - 1], query);
|
||||
|
||||
var results = AQL_EXECUTE(query);
|
||||
assertEqual([ 10, 11, 12, 13, 14, 15, 16, 17, 18, 19 ], results.json[0], query);
|
||||
assertEqual(0, results.stats.scannedFull);
|
||||
assertTrue(results.stats.scannedIndex > 0);
|
||||
},
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief test index usage
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
testUseIndexSubSubquery : function () {
|
||||
var query = "FOR i IN " + c.name() + " LIMIT 1 RETURN (FOR j IN " + c.name() + " FILTER j._key == i._key RETURN j.value)";
|
||||
|
||||
var plan = AQL_EXPLAIN(query).plan;
|
||||
var nodeTypes = plan.nodes.map(function(node) {
|
||||
return node.type;
|
||||
});
|
||||
|
||||
assertEqual("SingletonNode", nodeTypes[0], query);
|
||||
var idx = nodeTypes.indexOf("SubqueryNode");
|
||||
assertNotEqual(-1, idx, query);
|
||||
|
||||
var subNodeTypes = plan.nodes[idx].subquery.nodes.map(function(node) {
|
||||
return node.type;
|
||||
});
|
||||
assertNotEqual(-1, subNodeTypes.indexOf("IndexRangeNode"), query);
|
||||
assertEqual(-1, subNodeTypes.indexOf("SortNode"), query);
|
||||
assertEqual("ReturnNode", nodeTypes[nodeTypes.length - 1], query);
|
||||
|
||||
var results = AQL_EXECUTE(query);
|
||||
// require("internal").print(results);
|
||||
assertTrue(results.stats.scannedFull > 0); // for the outer query
|
||||
assertTrue(results.stats.scannedIndex > 0); // for the inner query
|
||||
}
|
||||
|
||||
};
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief executes the test suite
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
jsunity.run(optimizerIndexesTestSuite);
|
||||
|
||||
return jsunity.done();
|
||||
|
||||
// Local Variables:
|
||||
// mode: outline-minor
|
||||
// outline-regexp: "^\\(/// @brief\\|/// @addtogroup\\|// --SECTION--\\|/// @page\\|/// @}\\)"
|
||||
// End:
|
Loading…
Reference in New Issue