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

@ -197,52 +197,54 @@ bool Condition::findIndexForAndNode (AstNode const* node,
SortCondition const& sortCondition) {
// We can only iterate through a proper DNF
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.
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();
for (auto& idx : indexes) {
double filterCost = 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
double estimatedCost;
if (idx->supportsFilterCondition(node, reference, estimatedCost)) {
std::cout << "- INDEX SUPPORTS FILTER CONDITION\n";
// index supports the filter expression
// index supports the filter condition
filterCost = estimatedCost;
}
else {
std::cout << "- INDEX DOES NOT SUPPORT FILTER CONDITION\n";
// index does not support the filter condition
filterCost = MaxFilterCost;
}
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;
if (idx->isSorted() &&
idx->supportsSortCondition(&sortCondition, reference, estimatedCost)) {
std::cout << "- INDEX SUPPORTS SORT CONDITION\n";
// index supports the sort condition
sortCost = estimatedCost;
}
else {
std::cout << "- INDEX DOES NOT SUPPORT SORT CONDITION\n";
// index does not support the sort condition
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;
if (bestCost < totalCost) {
if (totalCost < bestCost) {
bestIndex = idx;
bestCost = totalCost;
}
@ -252,8 +254,6 @@ bool Condition::findIndexForAndNode (AstNode const* node,
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);
return true;

View File

@ -44,7 +44,7 @@ SortCondition::SortCondition (std::vector<std::pair<AstNode const*, bool>> const
: _expressions(expressions),
_unidirectional(true),
_onlyAttributeAccess(true) {
size_t const n = _expressions.size();
for (size_t i = 0; i < n; ++i) {
@ -65,15 +65,19 @@ SortCondition::SortCondition (std::vector<std::pair<AstNode const*, bool>> const
if (node->type == NODE_TYPE_REFERENCE) {
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) {
_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;
}
}
if (n == 0) {
_onlyAttributeAccess = false;
}
}
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) {
size_t const n = sorts.size();
for (size_t i = 0; i < n; ++i) {
if (_unidirectional && i > 0 && sorts[i].second != sorts[i - 1].second) {
_unidirectional = false;
@ -103,19 +108,73 @@ SortCondition::SortCondition (std::vector<std::pair<VariableId, bool>> const& so
fieldNames.emplace_back(triagens::basics::AttributeName(node->getStringValue()));
node = node->getMember(0);
}
if (node->type == NODE_TYPE_REFERENCE) {
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) {
_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;
}
}
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();
}
////////////////////////////////////////////////////////////////////////////////
/// @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
// -----------------------------------------------------------------------------
@ -108,7 +124,7 @@ namespace triagens {
/// @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

View File

@ -546,7 +546,10 @@ int EdgeIndex::sizeHint (size_t size) {
bool EdgeIndex::supportsFilterCondition (triagens::aql::AstNode const* node,
triagens::aql::Variable const* reference,
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);
}

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,
triagens::aql::Variable const* reference,
double& estimatedCost) const {
SimpleAttributeEqualityMatcher matcher(fieldNames());
SimpleAttributeEqualityMatcher matcher(fields());
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,
triagens::aql::Variable const* reference,
double& estimatedCost) const {
// by default, no filter conditions are supported
estimatedCost = 0.0;
return false;
}
@ -447,7 +448,8 @@ bool Index::supportsFilterCondition (triagens::aql::AstNode const* node,
bool Index::supportsSortCondition (triagens::aql::SortCondition const* sortCondition,
triagens::aql::Variable const* reference,
double& estimatedCost) const {
double& estimatedCost) const {
// by default, no sort conditions are supported
estimatedCost = 0.0;
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,
triagens::aql::Variable const* reference,
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);
}

View File

@ -34,6 +34,7 @@
#include "Aql/Ast.h"
#include "Aql/AstNode.h"
#include "Aql/Variable.h"
#include "Basics/AttributeNameParser.h"
#include "Indexes/Index.h"
#include "VocBase/vocbase.h"
@ -52,7 +53,7 @@ namespace triagens {
public:
SimpleAttributeEqualityMatcher (std::vector<std::vector<std::string>> const& attributes)
SimpleAttributeEqualityMatcher (std::vector<std::vector<triagens::basics::AttributeName>> const& attributes)
: _attributes(attributes) {
}
@ -217,7 +218,8 @@ namespace triagens {
bool match = true;
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;
break;
}
@ -243,7 +245,7 @@ namespace triagens {
/// @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);
}
estimatedCost = 1.0; // set to highest possible cost by default
return false;
}
bool SkiplistIndex::supportsSortCondition (triagens::aql::SortCondition const* sortCondition,
triagens::aql::Variable const* reference,
double& estimatedCost) const {
estimatedCost = 0.0;
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;
return true;
}
}
estimatedCost = 1.0;
return false;
}

View File

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