1
0
Fork 0

check filter condition and sort condition support for all index types

This commit is contained in:
Jan Steemann 2015-09-29 17:38:55 +02:00
parent 27bcd7ee84
commit 67de5480e8
10 changed files with 130 additions and 32 deletions

View File

@ -198,51 +198,53 @@ bool Condition::findIndexForAndNode (AstNode const* node,
// We can only iterate through a proper DNF // We can only iterate through a proper DNF
TRI_ASSERT(node->type == NODE_TYPE_OPERATOR_NARY_AND); TRI_ASSERT(node->type == NODE_TYPE_OPERATOR_NARY_AND);
static double const MaxFilterCost = 2.0;
static double const MaxSortCost = 2.0;
// This code is never responsible for the content of this pointer. // This code is never responsible for the content of this pointer.
Index const* bestIndex = nullptr; Index const* bestIndex = nullptr;
double bestCost = MaxFilterCost + MaxSortCost + std::numeric_limits<double>::epsilon();
static double const MaxFilterCost = 10.0;
static double const MaxSortCost = 10.0;
double bestCost = -1.0; // All costs are > 0, so if we have found one we can use it.
std::vector<Index const*> indexes = colNode->collection()->getIndexes(); std::vector<Index const*> indexes = colNode->collection()->getIndexes();
for (auto& idx : indexes) { for (auto& idx : indexes) {
double filterCost = 0.0; double filterCost = 0.0;
double sortCost = 0.0; double sortCost = 0.0;
std::cout << "CHECKING INDEX : " << triagens::basics::JsonHelper::toString(idx->getInternals()->toJson(TRI_UNKNOWN_MEM_ZONE, false).json()) << "\n";
// check if the index supports the filter expression // check if the index supports the filter expression
double estimatedCost; double estimatedCost;
if (idx->supportsFilterCondition(node, reference, estimatedCost)) { if (idx->supportsFilterCondition(node, reference, estimatedCost)) {
std::cout << "- INDEX SUPPORTS FILTER CONDITION\n"; // index supports the filter condition
// index supports the filter expression
filterCost = estimatedCost; filterCost = estimatedCost;
} }
else { else {
std::cout << "- INDEX DOES NOT SUPPORT FILTER CONDITION\n"; // index does not support the filter condition
filterCost = MaxFilterCost; filterCost = MaxFilterCost;
} }
if (! sortCondition.isEmpty() && if (! sortCondition.isEmpty() &&
sortCondition.isOnlyAttributeAccess()) { sortCondition.isOnlyAttributeAccess() &&
sortCondition.isUnidirectional()) {
// only go in here if we actually have a sort condition and it can in
// general be supported by an index. for this, a sort condition must not
// be empty, must consist only of attribute access, and all attributes
// must be sorted in the direction
double estimatedCost; double estimatedCost;
if (idx->isSorted() && if (idx->isSorted() &&
idx->supportsSortCondition(&sortCondition, reference, estimatedCost)) { idx->supportsSortCondition(&sortCondition, reference, estimatedCost)) {
std::cout << "- INDEX SUPPORTS SORT CONDITION\n"; // index supports the sort condition
sortCost = estimatedCost; sortCost = estimatedCost;
} }
else { else {
std::cout << "- INDEX DOES NOT SUPPORT SORT CONDITION\n"; // index does not support the sort condition
sortCost = MaxSortCost; sortCost = MaxSortCost;
} }
} }
std::cout << "- INDEX FILTER COST: " << filterCost << ", SORT COST: " << sortCost << "\n"; // std::cout << "INDEX: " << triagens::basics::JsonHelper::toString(idx->getInternals()->toJson(TRI_UNKNOWN_MEM_ZONE, false).json()) << ", FILTER COST: " << filterCost << ", SORT COST: " << sortCost << "\n";
double const totalCost = filterCost + sortCost; double const totalCost = filterCost + sortCost;
if (bestCost < totalCost) { if (totalCost < bestCost) {
bestIndex = idx; bestIndex = idx;
bestCost = totalCost; bestCost = totalCost;
} }
@ -252,8 +254,6 @@ bool Condition::findIndexForAndNode (AstNode const* node,
return false; return false;
} }
std::cout << "We can use indexes for var: " << reference->name << " in collection " << colNode->collection()->getName() << ":" << std::endl;
std::cout << "We use: " << bestIndex->toJson() << std::endl;
usedIndexes.emplace_back(bestIndex); usedIndexes.emplace_back(bestIndex);
return true; return true;

View File

@ -65,15 +65,19 @@ SortCondition::SortCondition (std::vector<std::pair<AstNode const*, bool>> const
if (node->type == NODE_TYPE_REFERENCE) { if (node->type == NODE_TYPE_REFERENCE) {
handled = true; handled = true;
_fields.emplace_back(std::make_pair(static_cast<Variable const*>(node->getData())->name, fieldNames)); _fields.emplace_back(std::make_pair(static_cast<Variable const*>(node->getData()), fieldNames));
} }
} }
if (! handled) { if (! handled) {
_fields.emplace_back(std::pair<std::string, std::vector<triagens::basics::AttributeName>>()); _fields.emplace_back(std::pair<Variable const*, std::vector<triagens::basics::AttributeName>>());
_onlyAttributeAccess = false; _onlyAttributeAccess = false;
} }
} }
if (n == 0) {
_onlyAttributeAccess = false;
}
} }
SortCondition::SortCondition (std::vector<std::pair<VariableId, bool>> const& sorts, SortCondition::SortCondition (std::vector<std::pair<VariableId, bool>> const& sorts,
@ -83,6 +87,7 @@ SortCondition::SortCondition (std::vector<std::pair<VariableId, bool>> const& so
_onlyAttributeAccess(true) { _onlyAttributeAccess(true) {
size_t const n = sorts.size(); size_t const n = sorts.size();
for (size_t i = 0; i < n; ++i) { for (size_t i = 0; i < n; ++i) {
if (_unidirectional && i > 0 && sorts[i].second != sorts[i - 1].second) { if (_unidirectional && i > 0 && sorts[i].second != sorts[i - 1].second) {
_unidirectional = false; _unidirectional = false;
@ -103,19 +108,73 @@ SortCondition::SortCondition (std::vector<std::pair<VariableId, bool>> const& so
fieldNames.emplace_back(triagens::basics::AttributeName(node->getStringValue())); fieldNames.emplace_back(triagens::basics::AttributeName(node->getStringValue()));
node = node->getMember(0); node = node->getMember(0);
} }
if (node->type == NODE_TYPE_REFERENCE) { if (node->type == NODE_TYPE_REFERENCE) {
handled = true; handled = true;
_fields.emplace_back(std::make_pair(static_cast<Variable const*>(node->getData())->name, fieldNames)); _fields.emplace_back(std::make_pair(static_cast<Variable const*>(node->getData()), fieldNames));
} }
} }
} }
if (! handled) { if (! handled) {
_fields.emplace_back(std::pair<std::string, std::vector<triagens::basics::AttributeName>>()); _fields.emplace_back(std::pair<Variable const*, std::vector<triagens::basics::AttributeName>>());
_onlyAttributeAccess = false; _onlyAttributeAccess = false;
} }
} }
if (n == 0) {
_onlyAttributeAccess = false;
}
}
// -----------------------------------------------------------------------------
// --SECTION-- public methods
// -----------------------------------------------------------------------------
////////////////////////////////////////////////////////////////////////////////
/// @brief returns the number of attributes in the sort condition covered
/// by the specified index fields
////////////////////////////////////////////////////////////////////////////////
size_t SortCondition::isCoveredBy (Variable const* reference,
std::vector<std::vector<triagens::basics::AttributeName>> const& indexAttributes) const {
size_t coveredAttributes = 0;
for (size_t i = 0; i < indexAttributes.size(); ++i) {
if (i >= _fields.size()) {
break;
}
if (reference != _fields[i].first) {
break;
}
auto const& fieldNames = _fields[i].second;
if (fieldNames.size() != indexAttributes[i].size()) {
// different attribute path
break;
}
bool found = true;
for (size_t j = 0; j < indexAttributes[i].size(); ++j) {
if (indexAttributes[i][j].shouldExpand ||
fieldNames[j] != indexAttributes[i][j].name) {
// expanded attribute or different attribute
found = false;
break;
}
}
if (! found) {
break;
}
// same attribute
++coveredAttributes;
}
return coveredAttributes;
} }
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------

View File

@ -92,6 +92,22 @@ namespace triagens {
return _fields.empty(); return _fields.empty();
} }
////////////////////////////////////////////////////////////////////////////////
/// @brief number of attributes in condition
////////////////////////////////////////////////////////////////////////////////
inline size_t numAttributes () const {
return _fields.size();
}
////////////////////////////////////////////////////////////////////////////////
/// @brief returns the number of attributes in the sort condition covered
/// by the specified index fields
////////////////////////////////////////////////////////////////////////////////
size_t isCoveredBy (Variable const*,
std::vector<std::vector<triagens::basics::AttributeName>> const&) const;
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
// --SECTION-- private variables // --SECTION-- private variables
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
@ -108,7 +124,7 @@ namespace triagens {
/// @brief fields used in the sort conditions /// @brief fields used in the sort conditions
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
std::vector<std::pair<std::string, std::vector<triagens::basics::AttributeName>>> _fields; std::vector<std::pair<Variable const*, std::vector<triagens::basics::AttributeName>>> _fields;
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
/// @brief whether or not the sort is unidirectional /// @brief whether or not the sort is unidirectional

View File

@ -546,7 +546,10 @@ int EdgeIndex::sizeHint (size_t size) {
bool EdgeIndex::supportsFilterCondition (triagens::aql::AstNode const* node, bool EdgeIndex::supportsFilterCondition (triagens::aql::AstNode const* node,
triagens::aql::Variable const* reference, triagens::aql::Variable const* reference,
double& estimatedCost) const { double& estimatedCost) const {
SimpleAttributeEqualityMatcher matcher({ { TRI_VOC_ATTRIBUTE_FROM }, { TRI_VOC_ATTRIBUTE_TO } }); SimpleAttributeEqualityMatcher matcher({
{ triagens::basics::AttributeName(TRI_VOC_ATTRIBUTE_FROM, false) },
{ triagens::basics::AttributeName(TRI_VOC_ATTRIBUTE_TO, false) }
});
return matcher.matchOne(this, node, reference, estimatedCost); return matcher.matchOne(this, node, reference, estimatedCost);
} }

View File

@ -702,7 +702,7 @@ int HashIndex::removeMulti (TRI_doc_mptr_t const* doc, bool isRollback) {
bool HashIndex::supportsFilterCondition (triagens::aql::AstNode const* node, bool HashIndex::supportsFilterCondition (triagens::aql::AstNode const* node,
triagens::aql::Variable const* reference, triagens::aql::Variable const* reference,
double& estimatedCost) const { double& estimatedCost) const {
SimpleAttributeEqualityMatcher matcher(fieldNames()); SimpleAttributeEqualityMatcher matcher(fields());
return matcher.matchAll(this, node, reference, estimatedCost); return matcher.matchAll(this, node, reference, estimatedCost);
} }

View File

@ -437,6 +437,7 @@ bool Index::hasBatchInsert () const {
bool Index::supportsFilterCondition (triagens::aql::AstNode const* node, bool Index::supportsFilterCondition (triagens::aql::AstNode const* node,
triagens::aql::Variable const* reference, triagens::aql::Variable const* reference,
double& estimatedCost) const { double& estimatedCost) const {
// by default, no filter conditions are supported
estimatedCost = 0.0; estimatedCost = 0.0;
return false; return false;
} }
@ -448,6 +449,7 @@ bool Index::supportsFilterCondition (triagens::aql::AstNode const* node,
bool Index::supportsSortCondition (triagens::aql::SortCondition const* sortCondition, bool Index::supportsSortCondition (triagens::aql::SortCondition const* sortCondition,
triagens::aql::Variable const* reference, triagens::aql::Variable const* reference,
double& estimatedCost) const { double& estimatedCost) const {
// by default, no sort conditions are supported
estimatedCost = 0.0; estimatedCost = 0.0;
return false; return false;
} }

View File

@ -277,7 +277,10 @@ void PrimaryIndex::invokeOnAllElements (std::function<void(TRI_doc_mptr_t*)> wor
bool PrimaryIndex::supportsFilterCondition (triagens::aql::AstNode const* node, bool PrimaryIndex::supportsFilterCondition (triagens::aql::AstNode const* node,
triagens::aql::Variable const* reference, triagens::aql::Variable const* reference,
double& estimatedCost) const { double& estimatedCost) const {
SimpleAttributeEqualityMatcher matcher({ { TRI_VOC_ATTRIBUTE_ID }, { TRI_VOC_ATTRIBUTE_KEY } }); SimpleAttributeEqualityMatcher matcher({
{ triagens::basics::AttributeName(TRI_VOC_ATTRIBUTE_ID, false) },
{ triagens::basics::AttributeName(TRI_VOC_ATTRIBUTE_KEY, false) }
});
return matcher.matchOne(this, node, reference, estimatedCost); return matcher.matchOne(this, node, reference, estimatedCost);
} }

View File

@ -34,6 +34,7 @@
#include "Aql/Ast.h" #include "Aql/Ast.h"
#include "Aql/AstNode.h" #include "Aql/AstNode.h"
#include "Aql/Variable.h" #include "Aql/Variable.h"
#include "Basics/AttributeNameParser.h"
#include "Indexes/Index.h" #include "Indexes/Index.h"
#include "VocBase/vocbase.h" #include "VocBase/vocbase.h"
@ -52,7 +53,7 @@ namespace triagens {
public: public:
SimpleAttributeEqualityMatcher (std::vector<std::vector<std::string>> const& attributes) SimpleAttributeEqualityMatcher (std::vector<std::vector<triagens::basics::AttributeName>> const& attributes)
: _attributes(attributes) { : _attributes(attributes) {
} }
@ -217,7 +218,8 @@ namespace triagens {
bool match = true; bool match = true;
for (size_t j = 0; j < _attributes[i].size(); ++j) { for (size_t j = 0; j < _attributes[i].size(); ++j) {
if (_attributes[i][j] != fieldNames[j]) { if (_attributes[i][j].shouldExpand ||
_attributes[i][j].name != fieldNames[j]) {
match = false; match = false;
break; break;
} }
@ -243,7 +245,7 @@ namespace triagens {
/// @brief array of attributes used for comparisons /// @brief array of attributes used for comparisons
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
std::vector<std::vector<std::string>> _attributes; std::vector<std::vector<triagens::basics::AttributeName>> _attributes;
}; };

View File

@ -1032,14 +1032,27 @@ bool SkiplistIndex::supportsFilterCondition (triagens::aql::AstNode const* node,
return estimatedCost * static_cast<double>(values); return estimatedCost * static_cast<double>(values);
} }
estimatedCost = 1.0; // set to highest possible cost by default
return false; return false;
} }
bool SkiplistIndex::supportsSortCondition (triagens::aql::SortCondition const* sortCondition, bool SkiplistIndex::supportsSortCondition (triagens::aql::SortCondition const* sortCondition,
triagens::aql::Variable const* reference, triagens::aql::Variable const* reference,
double& estimatedCost) const { double& estimatedCost) const {
TRI_ASSERT(sortCondition != nullptr);
if (! _useExpansion &&
sortCondition->isUnidirectional() &&
sortCondition->isOnlyAttributeAccess()) {
size_t const coveredAttributes = sortCondition->isCoveredBy(reference, _fields);
if (coveredAttributes >= sortCondition->numAttributes()) {
estimatedCost = 0.0; estimatedCost = 0.0;
return true;
}
}
estimatedCost = 1.0;
return false; return false;
} }

View File

@ -238,7 +238,7 @@ namespace triagens {
} }
bool isSorted () const override final { bool isSorted () const override final {
return false; return true;
} }
bool hasSelectivityEstimate () const override final { bool hasSelectivityEstimate () const override final {