From e0dcf4331d392a4f577085171c4dc5eab0fa7a18 Mon Sep 17 00:00:00 2001 From: Jan Steemann Date: Fri, 2 Oct 2015 17:39:04 +0200 Subject: [PATCH] finish IN optimizations in Condition --- arangod/Aql/AstNode.h | 10 +++++++++ arangod/Aql/Condition.cpp | 21 ++++++++++++------- .../Indexes/SimpleAttributeEqualityMatcher.h | 19 +++++------------ arangod/Indexes/SkiplistIndex.cpp | 19 +++++------------ 4 files changed, 34 insertions(+), 35 deletions(-) diff --git a/arangod/Aql/AstNode.h b/arangod/Aql/AstNode.h index e2905797e3..14ad61e991 100644 --- a/arangod/Aql/AstNode.h +++ b/arangod/Aql/AstNode.h @@ -36,6 +36,8 @@ #include "Basics/vector.h" #include "Basics/JsonHelper.h" +#include + namespace triagens { namespace basics { class StringBuffer; @@ -665,6 +667,14 @@ namespace triagens { return members.at(i); } +//////////////////////////////////////////////////////////////////////////////// +/// @brief sort members with a custom comparison function +//////////////////////////////////////////////////////////////////////////////// + + void sortMembers (std::function const& func) { + std::sort(members.begin(), members.end(), func); + } + //////////////////////////////////////////////////////////////////////////////// /// @brief reduces the number of members of the node //////////////////////////////////////////////////////////////////////////////// diff --git a/arangod/Aql/Condition.cpp b/arangod/Aql/Condition.cpp index 05c3c67cf3..6bb2122ea3 100644 --- a/arangod/Aql/Condition.cpp +++ b/arangod/Aql/Condition.cpp @@ -421,6 +421,19 @@ void Condition::optimize (ExecutionPlan* plan) { for (size_t j = 0; j < andNumMembers; ++j) { deduplicateInOperation(andNode->getMemberUnchecked(j)); } + // move IN operation to the front to make comparison code below simpler + andNode->sortMembers([] (AstNode const* lhs, AstNode const* rhs) -> bool { + if (lhs->type == NODE_TYPE_OPERATOR_BINARY_IN) { + if (rhs->type != NODE_TYPE_OPERATOR_BINARY_IN) { + return true; // IN < other + } + // fallthrough + } + else if (rhs->type == NODE_TYPE_OPERATOR_BINARY_IN) { + return false; // other > IN + } + return (lhs < rhs); // compare pointers to have a deterministic order + }); if (andNumMembers > 1) { // optimization is only necessary if an AND node has members @@ -456,7 +469,6 @@ void Condition::optimize (ExecutionPlan* plan) { } // multiple occurrences of the same attribute - std::cout << "ATTRIBUTE " << attributeName << " occurs in " << positions.size() << " positions\n"; auto leftNode = andNode->getMemberUnchecked(positions[0].first); ConditionPart current(variable, attributeName, 0, leftNode, positions[0].second); @@ -489,7 +501,6 @@ void Condition::optimize (ExecutionPlan* plan) { // merge IN with IN on same attribute TRI_ASSERT(rightNode->numMembers() == 2); -std::cout << "MERGING IN WITH IN\n"; auto merged = _ast->createNodeBinaryOperator(NODE_TYPE_OPERATOR_BINARY_IN, leftNode->getMemberUnchecked(0), mergeInOperations(leftNode, rightNode)); @@ -501,18 +512,16 @@ std::cout << "MERGING IN WITH IN\n"; // merge other comparison operator with IN TRI_ASSERT(rightNode->numMembers() == 2); - std::cout << "FOUND SOMETHING\n"; auto inNode = _ast->createNodeArray(); auto values = leftNode->getMemberUnchecked(1); for (size_t k = 0; k < values->numMembers(); ++k) { auto value = values->getMemberUnchecked(k); ConditionPart::ConditionPartCompareResult res = ConditionPart::ResultsTable - [CompareAstNodes(current.valueNode, value, false) + 1] + [CompareAstNodes(value, other.valueNode, false) + 1] [0 /*NODE_TYPE_OPERATOR_BINARY_EQ*/] [other.whichCompareOperation()]; -std::cout << "RES IS: " << res << "\n"; bool const keep = (res == CompareResult::OTHER_CONTAINED_IN_SELF || res == CompareResult::CONVERT_EQUAL); if (keep) { inNode->addMember(value); @@ -520,13 +529,11 @@ std::cout << "RES IS: " << res << "\n"; } if (inNode->numMembers() == 0) { -std::cout << "NOTHING LEFT AFTER MERGE\n"; // no values left after merging -> IMPOSSIBLE _root->removeMemberUnchecked(i); goto fastForwardToNextOrItem; } -std::cout << "STILL SOMETHING LEFT AFTER MERGE\n"; // use the new array of values andNode->getMemberUnchecked(positions[0].first)->changeMember(1, inNode); // remove the other operator diff --git a/arangod/Indexes/SimpleAttributeEqualityMatcher.h b/arangod/Indexes/SimpleAttributeEqualityMatcher.h index 6cdb03abc6..ca7e85e00e 100644 --- a/arangod/Indexes/SimpleAttributeEqualityMatcher.h +++ b/arangod/Indexes/SimpleAttributeEqualityMatcher.h @@ -284,24 +284,15 @@ namespace triagens { return false; } - if (access->type != triagens::aql::NODE_TYPE_ATTRIBUTE_ACCESS) { - return false; - } - - std::vector fieldNames; - while (access->type == triagens::aql::NODE_TYPE_ATTRIBUTE_ACCESS) { - fieldNames.emplace_back(std::string(access->getStringValue(), access->getStringLength())); - access = access->getMember(0); - } + std::pair> attributeData; - if (access->type != triagens::aql::NODE_TYPE_REFERENCE) { - return false; - } - - if (access->getData() != reference) { + if (! access->isAttributeAccessForVariable(attributeData) || + attributeData.first != reference) { // this access is not referencing this collection return false; } + + std::vector& fieldNames = attributeData.second; for (size_t i = 0; i < _attributes.size(); ++i) { if (_attributes[i].size() != fieldNames.size()) { diff --git a/arangod/Indexes/SkiplistIndex.cpp b/arangod/Indexes/SkiplistIndex.cpp index a1abd9d85e..e776ae41db 100644 --- a/arangod/Indexes/SkiplistIndex.cpp +++ b/arangod/Indexes/SkiplistIndex.cpp @@ -890,24 +890,15 @@ bool SkiplistIndex::accessFitsIndex (triagens::aql::AstNode const* access, return false; } - if (access->type != triagens::aql::NODE_TYPE_ATTRIBUTE_ACCESS) { - return false; - } - - std::vector fieldNames; - while (access->type == triagens::aql::NODE_TYPE_ATTRIBUTE_ACCESS) { - fieldNames.emplace_back(std::string(access->getStringValue(), access->getStringLength())); - access = access->getMember(0); - } + std::pair> attributeData; - if (access->type != triagens::aql::NODE_TYPE_REFERENCE) { - return false; - } - - if (access->getData() != reference) { + if (! access->isAttributeAccessForVariable(attributeData) || + attributeData.first != reference) { // this access is not referencing this collection return false; } + + std::vector& fieldNames = attributeData.second; triagens::aql::AstNodeType opType = op->type; if (opType == triagens::aql::NODE_TYPE_OPERATOR_BINARY_IN) {