1
0
Fork 0

clean up usage costs (#9237)

This commit is contained in:
Jan 2019-06-26 17:01:22 +02:00 committed by GitHub
parent 2fb159a8e2
commit 6f0c116130
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
27 changed files with 269 additions and 240 deletions

View File

@ -429,18 +429,11 @@ CostEstimate IndexNode::estimateCost() const {
auto root = _condition->root(); auto root = _condition->root();
for (size_t i = 0; i < _indexes.size(); ++i) { for (size_t i = 0; i < _indexes.size(); ++i) {
arangodb::aql::AstNode const* condition; Index::FilterCosts costs = Index::FilterCosts::defaultCosts(itemsInCollection);
if (root == nullptr || root->numMembers() <= i) {
condition = nullptr;
} else {
condition = root->getMember(i);
}
Index::UsageCosts costs; if (root != nullptr && root->numMembers() > i) {
if (condition != nullptr) { arangodb::aql::AstNode const* condition = root->getMember(i);
costs = _indexes[i].getIndex()->supportsFilterCondition(std::vector<std::shared_ptr<Index>>(), condition, _outVariable, itemsInCollection); costs = _indexes[i].getIndex()->supportsFilterCondition(std::vector<std::shared_ptr<Index>>(), condition, _outVariable, itemsInCollection);
} else {
costs = Index::UsageCosts::defaultsForFiltering(itemsInCollection);
} }
totalItems += costs.estimatedItems; totalItems += costs.estimatedItems;

View File

@ -219,7 +219,7 @@ bool ClusterIndex::matchesDefinition(VPackSlice const& info) const {
return Index::Compare(_info.slice(), info); return Index::Compare(_info.slice(), info);
} }
Index::UsageCosts ClusterIndex::supportsFilterCondition( Index::FilterCosts ClusterIndex::supportsFilterCondition(
std::vector<std::shared_ptr<arangodb::Index>> const& allIndexes, std::vector<std::shared_ptr<arangodb::Index>> const& allIndexes,
arangodb::aql::AstNode const* node, arangodb::aql::Variable const* reference, arangodb::aql::AstNode const* node, arangodb::aql::Variable const* reference,
size_t itemsInIndex) const { size_t itemsInIndex) const {
@ -232,10 +232,14 @@ Index::UsageCosts ClusterIndex::supportsFilterCondition(
SortedIndexAttributeMatcher::matchAttributes(this, node, reference, found, SortedIndexAttributeMatcher::matchAttributes(this, node, reference, found,
values, nonNullAttributes, values, nonNullAttributes,
/*skip evaluation (during execution)*/ false); /*skip evaluation (during execution)*/ false);
Index::UsageCosts costs;
costs.estimatedItems = values; Index::FilterCosts costs = Index::FilterCosts::defaultCosts(itemsInIndex);
/// TODO: estimatedCost? if (!found.empty()) {
costs.supportsCondition = !found.empty(); costs.supportsCondition = true;
costs.coveredAttributes = found.size();
costs.estimatedItems = values;
costs.estimatedCosts = static_cast<double>(values);
}
return costs; return costs;
} }
// MMFiles et al // MMFiles et al
@ -280,12 +284,12 @@ Index::UsageCosts ClusterIndex::supportsFilterCondition(
} }
TRI_ASSERT(_engineType == ClusterEngineType::MockEngine); TRI_ASSERT(_engineType == ClusterEngineType::MockEngine);
return Index::UsageCosts(); return Index::FilterCosts::defaultCosts(itemsInIndex);
} }
Index::UsageCosts ClusterIndex::supportsSortCondition(arangodb::aql::SortCondition const* sortCondition, Index::SortCosts ClusterIndex::supportsSortCondition(arangodb::aql::SortCondition const* sortCondition,
arangodb::aql::Variable const* reference, arangodb::aql::Variable const* reference,
size_t itemsInIndex) const { size_t itemsInIndex) const {
switch (_indexType) { switch (_indexType) {
case TRI_IDX_TYPE_PRIMARY_INDEX: case TRI_IDX_TYPE_PRIMARY_INDEX:
case TRI_IDX_TYPE_HASH_INDEX: { case TRI_IDX_TYPE_HASH_INDEX: {
@ -321,7 +325,7 @@ Index::UsageCosts ClusterIndex::supportsSortCondition(arangodb::aql::SortConditi
} }
TRI_ASSERT(_engineType == ClusterEngineType::MockEngine); TRI_ASSERT(_engineType == ClusterEngineType::MockEngine);
return Index::UsageCosts::defaultsForSorting(itemsInIndex, false); return Index::SortCosts::defaultCosts(itemsInIndex, false);
} }
/// @brief specializes the condition for use with the index /// @brief specializes the condition for use with the index

View File

@ -84,14 +84,14 @@ class ClusterIndex : public Index {
/// @brief Checks if this index is identical to the given definition /// @brief Checks if this index is identical to the given definition
bool matchesDefinition(arangodb::velocypack::Slice const&) const override; bool matchesDefinition(arangodb::velocypack::Slice const&) const override;
Index::UsageCosts supportsFilterCondition(std::vector<std::shared_ptr<arangodb::Index>> const& allIndexes, Index::FilterCosts supportsFilterCondition(std::vector<std::shared_ptr<arangodb::Index>> const& allIndexes,
arangodb::aql::AstNode const* node, arangodb::aql::AstNode const* node,
arangodb::aql::Variable const* reference, arangodb::aql::Variable const* reference,
size_t itemsInIndex) const override; size_t itemsInIndex) const override;
Index::UsageCosts supportsSortCondition(arangodb::aql::SortCondition const* sortCondition, Index::SortCosts supportsSortCondition(arangodb::aql::SortCondition const* sortCondition,
arangodb::aql::Variable const* reference, arangodb::aql::Variable const* reference,
size_t itemsInIndex) const override; size_t itemsInIndex) const override;
/// @brief specializes the condition for use with the index /// @brief specializes the condition for use with the index
arangodb::aql::AstNode* specializeCondition(arangodb::aql::AstNode* node, arangodb::aql::AstNode* specializeCondition(arangodb::aql::AstNode* node,

View File

@ -177,6 +177,45 @@ std::string defaultIndexName(VPackSlice const& slice) {
} }
} // namespace } // namespace
Index::FilterCosts Index::FilterCosts::zeroCosts() {
Index::FilterCosts costs;
costs.supportsCondition = true;
costs.coveredAttributes = 0;
costs.estimatedItems = 0;
costs.estimatedCosts = 0;
return costs;
}
Index::FilterCosts Index::FilterCosts::defaultCosts(size_t itemsInIndex) {
Index::FilterCosts costs;
costs.supportsCondition = false;
costs.coveredAttributes = 0;
costs.estimatedItems = itemsInIndex;
costs.estimatedCosts = static_cast<double>(itemsInIndex);
return costs;
}
Index::SortCosts Index::SortCosts::zeroCosts(size_t coveredAttributes) {
Index::SortCosts costs;
costs.coveredAttributes = coveredAttributes;
costs.supportsCondition = true;
costs.estimatedCosts = 0;
return costs;
}
Index::SortCosts Index::SortCosts::defaultCosts(size_t itemsInIndex, bool isPersistent) {
Index::SortCosts costs;
TRI_ASSERT(!costs.supportsCondition);
costs.coveredAttributes = 0;
costs.estimatedCosts = itemsInIndex > 0 ? (itemsInIndex * std::log2(static_cast<double>(itemsInIndex))) : 0.0;
if (isPersistent) {
// slightly penalize this type of index against other indexes which
// are in memory
costs.estimatedCosts *= 1.05;
}
return costs;
}
// If the Index is on a coordinator instance the index may not access the // If the Index is on a coordinator instance the index may not access the
// logical collection because it could be gone! // logical collection because it could be gone!
@ -630,20 +669,20 @@ Result Index::drop() {
} }
/// @brief default implementation for supportsFilterCondition /// @brief default implementation for supportsFilterCondition
Index::UsageCosts Index::supportsFilterCondition(std::vector<std::shared_ptr<arangodb::Index>> const&, Index::FilterCosts Index::supportsFilterCondition(std::vector<std::shared_ptr<arangodb::Index>> const&,
arangodb::aql::AstNode const* /* node */, arangodb::aql::AstNode const* /* node */,
arangodb::aql::Variable const* /* reference */, arangodb::aql::Variable const* /* reference */,
size_t itemsInIndex) const { size_t itemsInIndex) const {
// by default, no filter conditions are supported // by default no filter conditions are supported
return Index::UsageCosts::defaultsForFiltering(itemsInIndex); return Index::FilterCosts::defaultCosts(itemsInIndex);
} }
/// @brief default implementation for supportsSortCondition /// @brief default implementation for supportsSortCondition
Index::UsageCosts Index::supportsSortCondition(arangodb::aql::SortCondition const* /* sortCondition */, Index::SortCosts Index::supportsSortCondition(arangodb::aql::SortCondition const* /* sortCondition */,
arangodb::aql::Variable const* /* node */, arangodb::aql::Variable const* /* node */,
size_t itemsInIndex) const { size_t itemsInIndex) const {
// by default, no sort conditions are supported // by default no sort conditions are supported
return Index::UsageCosts::defaultsForSorting(itemsInIndex, this->isPersistent()); return Index::SortCosts::defaultCosts(itemsInIndex, this->isPersistent());
} }
arangodb::aql::AstNode* Index::specializeCondition(arangodb::aql::AstNode* /* node */, arangodb::aql::AstNode* Index::specializeCondition(arangodb::aql::AstNode* /* node */,

View File

@ -108,48 +108,40 @@ class Index {
enum OperationMode { normal, internal, rollback }; enum OperationMode { normal, internal, rollback };
/// @brief: helper struct returned by index methods that determine the costs /// @brief: helper struct returned by index methods that determine the costs
/// of index usage /// of index usage for filtering
struct UsageCosts { struct FilterCosts {
/// @brief whether or not the index supports the filter condition/sort clause /// @brief whether or not the index supports the filter condition
bool supportsCondition = false; bool supportsCondition = false;
/// @brief number of attributes covered by this index /// @brief number of attributes of filter condition covered by this index
size_t coveredAttributes = 0; size_t coveredAttributes = 0;
/// @brief estimated items to be returned for this condition /// @brief estimated items to be returned for this condition.
size_t estimatedItems = 0; size_t estimatedItems = 0;
/// @brief estimated costs for this filter condition/sort clause /// @brief estimated costs for this filter condition
double estimatedCosts = 0.0; double estimatedCosts = 0.0;
static UsageCosts zeroCosts() { static FilterCosts zeroCosts();
UsageCosts costs;
costs.estimatedItems = 0;
costs.estimatedCosts = 0;
costs.supportsCondition = true;
return costs;
}
static UsageCosts defaultsForFiltering(size_t itemsInIndex) { static FilterCosts defaultCosts(size_t itemsInIndex);
UsageCosts costs; };
costs.estimatedItems = itemsInIndex;
costs.estimatedCosts = static_cast<double>(itemsInIndex); /// @brief: helper struct returned by index methods that determine the costs
TRI_ASSERT(!costs.supportsCondition); /// of index usage
return costs; struct SortCosts {
} /// @brief whether or not the index supports the sort clause
bool supportsCondition = false;
/// @brief number of attributes of the sort clause covered by this index
size_t coveredAttributes = 0;
static UsageCosts defaultsForSorting(size_t itemsInIndex, bool isPersistent) { /// @brief estimated costs for this sort clause
UsageCosts costs; double estimatedCosts = 0.0;
costs.estimatedItems = itemsInIndex;
costs.estimatedCosts = itemsInIndex > 0 ? (itemsInIndex * std::log2(static_cast<double>(itemsInIndex))) : 0.0; static SortCosts zeroCosts(size_t coveredAttributes);
if (isPersistent) {
// slightly penalize this type of index against other indexes which static SortCosts defaultCosts(size_t itemsInIndex, bool isPersistent);
// are in memory
costs.estimatedCosts *= 1.05;
}
TRI_ASSERT(!costs.supportsCondition);
return costs;
}
}; };
public: public:
@ -392,16 +384,16 @@ class Index {
/// @brief whether or not the filter condition is supported by the index /// @brief whether or not the filter condition is supported by the index
/// returns detailed information about the costs associated with using this index /// returns detailed information about the costs associated with using this index
virtual UsageCosts supportsFilterCondition(std::vector<std::shared_ptr<arangodb::Index>> const& allIndexes, virtual FilterCosts supportsFilterCondition(std::vector<std::shared_ptr<arangodb::Index>> const& allIndexes,
arangodb::aql::AstNode const* node, arangodb::aql::AstNode const* node,
arangodb::aql::Variable const* reference, arangodb::aql::Variable const* reference,
size_t itemsInIndex) const; size_t itemsInIndex) const;
/// @brief whether or not the sort condition is supported by the index /// @brief whether or not the sort condition is supported by the index
/// returns detailed information about the costs associated with using this index /// returns detailed information about the costs associated with using this index
virtual UsageCosts supportsSortCondition(arangodb::aql::SortCondition const* sortCondition, virtual SortCosts supportsSortCondition(arangodb::aql::SortCondition const* sortCondition,
arangodb::aql::Variable const* reference, arangodb::aql::Variable const* reference,
size_t itemsInIndex) const; size_t itemsInIndex) const;
/// @brief specialize the condition for use with this index. this will remove all /// @brief specialize the condition for use with this index. this will remove all
/// elements from the condition that are not supported by the index. /// elements from the condition that are not supported by the index.

View File

@ -34,62 +34,62 @@ using namespace arangodb;
SimpleAttributeEqualityMatcher::SimpleAttributeEqualityMatcher( SimpleAttributeEqualityMatcher::SimpleAttributeEqualityMatcher(
std::vector<std::vector<arangodb::basics::AttributeName>> const& attributes) std::vector<std::vector<arangodb::basics::AttributeName>> const& attributes)
: _attributes(attributes), _found() {} : _attributes(attributes) {}
/// @brief match a single of the attributes /// @brief match a single of the attributes
/// this is used for the primary index and the edge index /// this is used for the primary index and the edge index
Index::UsageCosts SimpleAttributeEqualityMatcher::matchOne(arangodb::Index const* index, Index::FilterCosts SimpleAttributeEqualityMatcher::matchOne(arangodb::Index const* index,
arangodb::aql::AstNode const* node, arangodb::aql::AstNode const* node,
arangodb::aql::Variable const* reference, arangodb::aql::Variable const* reference,
size_t itemsInIndex) { size_t itemsInIndex) {
std::unordered_set<std::string> nonNullAttributes; std::unordered_set<std::string> nonNullAttributes;
_found.clear(); _found.clear();
size_t const n = node->numMembers(); size_t const n = node->numMembers();
for (size_t i = 0; i < n; ++i) { for (size_t i = 0; i < n; ++i) {
arangodb::aql::AstNode const* which = nullptr;
size_t values = 1;
auto op = node->getMemberUnchecked(i); auto op = node->getMemberUnchecked(i);
if (op->type == arangodb::aql::NODE_TYPE_OPERATOR_BINARY_EQ) { if (op->type == arangodb::aql::NODE_TYPE_OPERATOR_BINARY_EQ) {
TRI_ASSERT(op->numMembers() == 2); TRI_ASSERT(op->numMembers() == 2);
// EQ is symmetric // EQ is symmetric
int which = -1; if (accessFitsIndex(index, op->getMemberUnchecked(0), op->getMemberUnchecked(1), op,
if (accessFitsIndex(index, op->getMember(0), op->getMember(1), op,
reference, nonNullAttributes, false)) { reference, nonNullAttributes, false)) {
which = 0; which = op->getMemberUnchecked(0);
} else if (accessFitsIndex(index, op->getMember(1), op->getMember(0), op, } else if (accessFitsIndex(index, op->getMemberUnchecked(1), op->getMemberUnchecked(0), op,
reference, nonNullAttributes, false)) { reference, nonNullAttributes, false)) {
which = 1; which = op->getMemberUnchecked(1);
}
if (which >= 0) {
// we can use the index
return calculateIndexCosts(index, op->getMember(which), itemsInIndex);
} }
} else if (op->type == arangodb::aql::NODE_TYPE_OPERATOR_BINARY_IN) { } else if (op->type == arangodb::aql::NODE_TYPE_OPERATOR_BINARY_IN) {
TRI_ASSERT(op->numMembers() == 2); TRI_ASSERT(op->numMembers() == 2);
if (accessFitsIndex(index, op->getMember(0), op->getMember(1), op, if (accessFitsIndex(index, op->getMemberUnchecked(0), op->getMemberUnchecked(1), op,
reference, nonNullAttributes, false)) { reference, nonNullAttributes, false)) {
// we can use the index // we can use the index
// use slightly different cost calculation for IN than for EQ // use slightly different cost calculation for IN than for EQ
Index::UsageCosts costs = calculateIndexCosts(index, op->getMember(0), itemsInIndex); which = op->getMemberUnchecked(0);
size_t values = estimateNumberOfArrayMembers(op->getMember(1)); values = estimateNumberOfArrayMembers(op->getMemberUnchecked(1));
costs.estimatedItems *= values;
costs.estimatedCosts *= values;
return costs;
} }
} }
if (which != nullptr) {
// we can use the index
return calculateIndexCosts(index, which, itemsInIndex * values, 1);
}
} }
// set to defaults // set to defaults
return Index::UsageCosts::defaultsForFiltering(itemsInIndex); return Index::FilterCosts::defaultCosts(itemsInIndex);
} }
/// @brief match all of the attributes, in any order /// @brief match all of the attributes, in any order
/// this is used for the hash index /// this is used for the hash index
Index::UsageCosts SimpleAttributeEqualityMatcher::matchAll(arangodb::Index const* index, Index::FilterCosts SimpleAttributeEqualityMatcher::matchAll(arangodb::Index const* index,
arangodb::aql::AstNode const* node, arangodb::aql::AstNode const* node,
arangodb::aql::Variable const* reference, arangodb::aql::Variable const* reference,
size_t itemsInIndex) { size_t itemsInIndex) {
std::unordered_set<std::string> nonNullAttributes; std::unordered_set<std::string> nonNullAttributes;
_found.clear(); _found.clear();
arangodb::aql::AstNode const* which = nullptr; arangodb::aql::AstNode const* which = nullptr;
@ -98,7 +98,7 @@ Index::UsageCosts SimpleAttributeEqualityMatcher::matchAll(arangodb::Index const
size_t const n = node->numMembers(); size_t const n = node->numMembers();
for (size_t i = 0; i < n; ++i) { for (size_t i = 0; i < n; ++i) {
auto op = node->getMember(i); auto op = node->getMemberUnchecked(i);
if (index->sparse() && (op->type == arangodb::aql::NODE_TYPE_OPERATOR_BINARY_NE || if (index->sparse() && (op->type == arangodb::aql::NODE_TYPE_OPERATOR_BINARY_NE ||
op->type == arangodb::aql::NODE_TYPE_OPERATOR_BINARY_GT)) { op->type == arangodb::aql::NODE_TYPE_OPERATOR_BINARY_GT)) {
@ -136,13 +136,16 @@ Index::UsageCosts SimpleAttributeEqualityMatcher::matchAll(arangodb::Index const
break; break;
} }
} }
if (values == 0) {
values = 1;
}
Index::FilterCosts costs = Index::FilterCosts::defaultCosts(itemsInIndex * values);
if (_found.size() == _attributes.size()) { if (_found.size() == _attributes.size()) {
// can only use this index if all index attributes are covered by the // can only use this index if all index attributes are covered by the
// condition // condition
if (values == 0) {
values = 1;
}
if (_found.size() == 1) { if (_found.size() == 1) {
// single-attribute index // single-attribute index
TRI_ASSERT(which != nullptr); TRI_ASSERT(which != nullptr);
@ -151,14 +154,11 @@ Index::UsageCosts SimpleAttributeEqualityMatcher::matchAll(arangodb::Index const
which = nullptr; which = nullptr;
} }
Index::UsageCosts costs = calculateIndexCosts(index, which, itemsInIndex); costs = calculateIndexCosts(index, which, itemsInIndex * values, _found.size());
costs.estimatedItems *= values;
costs.estimatedCosts *= static_cast<double>(values);
return costs;
} }
// set to defaults // return defaults
return Index::UsageCosts::defaultsForFiltering(itemsInIndex); return costs;
} }
/// @brief specialize the condition for the index /// @brief specialize the condition for the index
@ -298,14 +298,15 @@ arangodb::aql::AstNode* SimpleAttributeEqualityMatcher::specializeAll(
/// that will return in average /// that will return in average
/// cost values have no special meaning, except that multiple cost values are /// cost values have no special meaning, except that multiple cost values are
/// comparable, and lower values mean lower costs /// comparable, and lower values mean lower costs
Index::UsageCosts SimpleAttributeEqualityMatcher::calculateIndexCosts( Index::FilterCosts SimpleAttributeEqualityMatcher::calculateIndexCosts(
arangodb::Index const* index, arangodb::aql::AstNode const* attribute, arangodb::Index const* index, arangodb::aql::AstNode const* attribute,
size_t itemsInIndex) const { size_t itemsInIndex, size_t coveredAttributes) const {
// note: attribute will be set to the index attribute for single-attribute // note: attribute will be set to the index attribute for single-attribute
// indexes such as the primary and edge indexes, and is a nullptr for the // indexes such as the primary and edge indexes, and is a nullptr for the
// other indexes // other indexes
Index::UsageCosts costs; Index::FilterCosts costs;
costs.supportsCondition = true; costs.supportsCondition = true;
costs.coveredAttributes = coveredAttributes;
if (index->unique() || index->implicitlyUnique()) { if (index->unique() || index->implicitlyUnique()) {
// index is unique, and the condition covers all attributes // index is unique, and the condition covers all attributes

View File

@ -45,17 +45,17 @@ class SimpleAttributeEqualityMatcher {
public: public:
/// @brief match a single of the attributes /// @brief match a single of the attributes
/// this is used for the primary index and the edge index /// this is used for the primary index and the edge index
Index::UsageCosts matchOne(arangodb::Index const* index, Index::FilterCosts matchOne(arangodb::Index const* index,
arangodb::aql::AstNode const* node, arangodb::aql::AstNode const* node,
arangodb::aql::Variable const* reference, arangodb::aql::Variable const* reference,
size_t itemsInIndex); size_t itemsInIndex);
/// @brief match all of the attributes, in any order /// @brief match all of the attributes, in any order
/// this is used for the hash index /// this is used for the hash index
Index::UsageCosts matchAll(arangodb::Index const* index, Index::FilterCosts matchAll(arangodb::Index const* index,
arangodb::aql::AstNode const* node, arangodb::aql::AstNode const* node,
arangodb::aql::Variable const* reference, arangodb::aql::Variable const* reference,
size_t itemsInIndex); size_t itemsInIndex);
/// @brief get the condition parts that the index is responsible for /// @brief get the condition parts that the index is responsible for
/// this is used for the primary index and the edge index /// this is used for the primary index and the edge index
@ -84,8 +84,9 @@ class SimpleAttributeEqualityMatcher {
/// that will return in average /// that will return in average
/// cost values have no special meaning, except that multiple cost values are /// cost values have no special meaning, except that multiple cost values are
/// comparable, and lower values mean lower costs /// comparable, and lower values mean lower costs
Index::UsageCosts calculateIndexCosts(arangodb::Index const* index, Index::FilterCosts calculateIndexCosts(arangodb::Index const* index,
arangodb::aql::AstNode const* attribute, size_t itemsInIndex) const; arangodb::aql::AstNode const* attribute,
size_t itemsInIndex, size_t coveredAttributes) const;
/// @brief whether or not the access fits /// @brief whether or not the access fits
bool accessFitsIndex(arangodb::Index const*, arangodb::aql::AstNode const*, bool accessFitsIndex(arangodb::Index const*, arangodb::aql::AstNode const*,

View File

@ -187,7 +187,7 @@ void SortedIndexAttributeMatcher::matchAttributes(
} }
} }
Index::UsageCosts SortedIndexAttributeMatcher::supportsFilterCondition( Index::FilterCosts SortedIndexAttributeMatcher::supportsFilterCondition(
std::vector<std::shared_ptr<arangodb::Index>> const& allIndexes, std::vector<std::shared_ptr<arangodb::Index>> const& allIndexes,
arangodb::Index const* idx, arangodb::aql::AstNode const* node, arangodb::Index const* idx, arangodb::aql::AstNode const* node,
arangodb::aql::Variable const* reference, size_t itemsInIndex) { arangodb::aql::Variable const* reference, size_t itemsInIndex) {
@ -198,8 +198,6 @@ Index::UsageCosts SortedIndexAttributeMatcher::supportsFilterCondition(
} }
} }
Index::UsageCosts costs;
std::unordered_map<size_t, std::vector<arangodb::aql::AstNode const*>> found; std::unordered_map<size_t, std::vector<arangodb::aql::AstNode const*>> found;
std::unordered_set<std::string> nonNullAttributes; std::unordered_set<std::string> nonNullAttributes;
size_t values = 0; size_t values = 0;
@ -209,7 +207,7 @@ Index::UsageCosts SortedIndexAttributeMatcher::supportsFilterCondition(
size_t attributesCovered = 0; size_t attributesCovered = 0;
size_t attributesCoveredByEquality = 0; size_t attributesCoveredByEquality = 0;
double equalityReductionFactor = 20.0; double equalityReductionFactor = 20.0;
costs.estimatedCosts = static_cast<double>(itemsInIndex); double estimatedCosts = static_cast<double>(itemsInIndex);
for (size_t i = 0; i < idx->fields().size(); ++i) { for (size_t i = 0; i < idx->fields().size(); ++i) {
auto it = found.find(i); auto it = found.find(i);
@ -238,7 +236,7 @@ Index::UsageCosts SortedIndexAttributeMatcher::supportsFilterCondition(
++attributesCovered; ++attributesCovered;
if (containsEquality) { if (containsEquality) {
++attributesCoveredByEquality; ++attributesCoveredByEquality;
costs.estimatedCosts /= equalityReductionFactor; estimatedCosts /= equalityReductionFactor;
// decrease the effect of the equality reduction factor // decrease the effect of the equality reduction factor
equalityReductionFactor *= 0.25; equalityReductionFactor *= 0.25;
@ -251,10 +249,10 @@ Index::UsageCosts SortedIndexAttributeMatcher::supportsFilterCondition(
if (nodes.size() >= 2) { if (nodes.size() >= 2) {
// at least two (non-equality) conditions. probably a range with lower // at least two (non-equality) conditions. probably a range with lower
// and upper bound defined // and upper bound defined
costs.estimatedCosts /= 7.5; estimatedCosts /= 7.5;
} else { } else {
// one (non-equality). this is either a lower or a higher bound // one (non-equality). this is either a lower or a higher bound
costs.estimatedCosts /= 2.0; estimatedCosts /= 2.0;
} }
} }
@ -264,26 +262,27 @@ Index::UsageCosts SortedIndexAttributeMatcher::supportsFilterCondition(
if (values == 0) { if (values == 0) {
values = 1; values = 1;
} }
Index::FilterCosts costs = Index::FilterCosts::defaultCosts(itemsInIndex);
costs.coveredAttributes = attributesCovered;
if (attributesCoveredByEquality == idx->fields().size() && if (attributesCoveredByEquality == idx->fields().size() &&
(idx->unique() || idx->implicitlyUnique())) { (idx->unique() || idx->implicitlyUnique())) {
// index is unique and condition covers all attributes by equality // index is unique and condition covers all attributes by equality
costs.coveredAttributes = attributesCovered;
costs.supportsCondition = true; costs.supportsCondition = true;
if (itemsInIndex == 0) { if (itemsInIndex == 0) {
costs.estimatedItems = 0; costs.estimatedItems = 0;
costs.estimatedCosts = 0.0; costs.estimatedCosts = 0.0;
return costs; } else {
costs.estimatedItems = values;
// ALTERNATIVE: estimatedCost = static_cast<double>(estimatedItems * values);
costs.estimatedCosts = (std::max)(static_cast<double>(1),
std::log2(static_cast<double>(itemsInIndex)) * values);
// cost is already low... now slightly prioritize unique indexes
costs.estimatedCosts *= 0.995 - 0.05 * (idx->fields().size() - 1);
} }
costs.estimatedItems = values;
// ALTERNATIVE: estimatedCost = static_cast<double>(estimatedItems * values);
costs.estimatedCosts = (std::max)(static_cast<double>(1),
std::log2(static_cast<double>(itemsInIndex)) * values);
// cost is already low... now slightly prioritize unique indexes
costs.estimatedCosts *= 0.995 - 0.05 * (idx->fields().size() - 1);
return costs; return costs;
} }
@ -293,8 +292,9 @@ Index::UsageCosts SortedIndexAttributeMatcher::supportsFilterCondition(
// or the index is sparse and all attributes are covered by the condition, // or the index is sparse and all attributes are covered by the condition,
// then it can be used (note: additional checks for condition parts in // then it can be used (note: additional checks for condition parts in
// sparse indexes are contained in Index::canUseConditionPart) // sparse indexes are contained in Index::canUseConditionPart)
costs.supportsCondition = true;
costs.estimatedItems = static_cast<size_t>( costs.estimatedItems = static_cast<size_t>(
(std::max)(static_cast<size_t>(costs.estimatedCosts * values), static_cast<size_t>(1))); (std::max)(static_cast<size_t>(estimatedCosts * values), static_cast<size_t>(1)));
// check if the index has a selectivity estimate ready // check if the index has a selectivity estimate ready
if (idx->hasSelectivityEstimate() && if (idx->hasSelectivityEstimate() &&
@ -357,21 +357,20 @@ Index::UsageCosts SortedIndexAttributeMatcher::supportsFilterCondition(
// slightly prefer indexes that cover more attributes // slightly prefer indexes that cover more attributes
costs.estimatedCosts -= (attributesCovered - 1) * 0.02; costs.estimatedCosts -= (attributesCovered - 1) * 0.02;
} }
costs.coveredAttributes = attributesCovered;
costs.supportsCondition = true;
return costs; return costs;
} }
// index does not help for this condition // index does not help for this condition
return Index::UsageCosts::defaultsForFiltering(itemsInIndex); TRI_ASSERT(!costs.supportsCondition);
return costs;
} }
Index::UsageCosts SortedIndexAttributeMatcher::supportsSortCondition( Index::SortCosts SortedIndexAttributeMatcher::supportsSortCondition(
arangodb::Index const* idx, arangodb::aql::SortCondition const* sortCondition, arangodb::Index const* idx, arangodb::aql::SortCondition const* sortCondition,
arangodb::aql::Variable const* reference, size_t itemsInIndex) { arangodb::aql::Variable const* reference, size_t itemsInIndex) {
TRI_ASSERT(sortCondition != nullptr); TRI_ASSERT(sortCondition != nullptr);
Index::UsageCosts costs; Index::SortCosts costs = Index::SortCosts::defaultCosts(itemsInIndex, idx->isPersistent());
if (!idx->sparse() || if (!idx->sparse() ||
sortCondition->onlyUsesNonNullSortAttributes(idx->fields())) { sortCondition->onlyUsesNonNullSortAttributes(idx->fields())) {
@ -390,7 +389,6 @@ Index::UsageCosts SortedIndexAttributeMatcher::supportsSortCondition(
costs.estimatedCosts *= 4; costs.estimatedCosts *= 4;
} }
costs.supportsCondition = true; costs.supportsCondition = true;
return costs;
} else if (costs.coveredAttributes > 0) { } else if (costs.coveredAttributes > 0) {
costs.estimatedCosts = (itemsInIndex / costs.coveredAttributes) * costs.estimatedCosts = (itemsInIndex / costs.coveredAttributes) *
std::log2(static_cast<double>(itemsInIndex)); std::log2(static_cast<double>(itemsInIndex));
@ -399,12 +397,11 @@ Index::UsageCosts SortedIndexAttributeMatcher::supportsSortCondition(
costs.estimatedCosts *= 4; costs.estimatedCosts *= 4;
} }
costs.supportsCondition = true; costs.supportsCondition = true;
return costs;
} }
} }
} }
return Index::UsageCosts::defaultsForSorting(itemsInIndex, idx->isPersistent()); return costs;
} }
/// @brief specializes the condition for use with the index /// @brief specializes the condition for use with the index

View File

@ -39,16 +39,16 @@ class Index;
namespace SortedIndexAttributeMatcher { namespace SortedIndexAttributeMatcher {
Index::UsageCosts supportsFilterCondition(std::vector<std::shared_ptr<arangodb::Index>> const& allIndexes, Index::FilterCosts supportsFilterCondition(std::vector<std::shared_ptr<arangodb::Index>> const& allIndexes,
arangodb::Index const* index, arangodb::Index const* index,
arangodb::aql::AstNode const* node, arangodb::aql::AstNode const* node,
arangodb::aql::Variable const* reference, arangodb::aql::Variable const* reference,
size_t itemsInIndex); size_t itemsInIndex);
Index::UsageCosts supportsSortCondition(arangodb::Index const* index, Index::SortCosts supportsSortCondition(arangodb::Index const* index,
arangodb::aql::SortCondition const* sortCondition, arangodb::aql::SortCondition const* sortCondition,
arangodb::aql::Variable const* reference, arangodb::aql::Variable const* reference,
size_t itemsInIndex); size_t itemsInIndex);
/// @brief specializes the condition for use with the index /// @brief specializes the condition for use with the index
arangodb::aql::AstNode* specializeCondition(arangodb::Index const* index, arangodb::aql::AstNode* specializeCondition(arangodb::Index const* index,

View File

@ -384,7 +384,7 @@ Result MMFilesEdgeIndex::sizeHint(transaction::Methods& trx, size_t size) {
} }
/// @brief checks whether the index supports the condition /// @brief checks whether the index supports the condition
Index::UsageCosts MMFilesEdgeIndex::supportsFilterCondition( Index::FilterCosts MMFilesEdgeIndex::supportsFilterCondition(
std::vector<std::shared_ptr<arangodb::Index>> const&, std::vector<std::shared_ptr<arangodb::Index>> const&,
arangodb::aql::AstNode const* node, arangodb::aql::Variable const* reference, arangodb::aql::AstNode const* node, arangodb::aql::Variable const* reference,
size_t itemsInIndex) const { size_t itemsInIndex) const {

View File

@ -180,10 +180,10 @@ class MMFilesEdgeIndex final : public MMFilesIndex {
TRI_MMFilesEdgeIndexHash_t* to() const { return _edgesTo.get(); } TRI_MMFilesEdgeIndexHash_t* to() const { return _edgesTo.get(); }
Index::UsageCosts supportsFilterCondition(std::vector<std::shared_ptr<arangodb::Index>> const& allIndexes, Index::FilterCosts supportsFilterCondition(std::vector<std::shared_ptr<arangodb::Index>> const& allIndexes,
arangodb::aql::AstNode const* node, arangodb::aql::AstNode const* node,
arangodb::aql::Variable const* reference, arangodb::aql::Variable const* reference,
size_t itemsInIndex) const override; size_t itemsInIndex) const override;
std::unique_ptr<IndexIterator> iteratorForCondition(transaction::Methods* trx, std::unique_ptr<IndexIterator> iteratorForCondition(transaction::Methods* trx,
arangodb::aql::AstNode const* node, arangodb::aql::AstNode const* node,

View File

@ -845,7 +845,7 @@ int MMFilesHashIndex::removeMultiElement(transaction::Methods* trx,
} }
/// @brief checks whether the index supports the condition /// @brief checks whether the index supports the condition
Index::UsageCosts MMFilesHashIndex::supportsFilterCondition( Index::FilterCosts MMFilesHashIndex::supportsFilterCondition(
std::vector<std::shared_ptr<arangodb::Index>> const&, std::vector<std::shared_ptr<arangodb::Index>> const&,
arangodb::aql::AstNode const* node, arangodb::aql::Variable const* reference, arangodb::aql::AstNode const* node, arangodb::aql::Variable const* reference,
size_t itemsInIndex) const { size_t itemsInIndex) const {

View File

@ -268,10 +268,10 @@ class MMFilesHashIndex final : public MMFilesPathBasedIndex {
Result sizeHint(transaction::Methods& trx, size_t size) override; Result sizeHint(transaction::Methods& trx, size_t size) override;
Index::UsageCosts supportsFilterCondition(std::vector<std::shared_ptr<arangodb::Index>> const& allIndexes, Index::FilterCosts supportsFilterCondition(std::vector<std::shared_ptr<arangodb::Index>> const& allIndexes,
arangodb::aql::AstNode const* node, arangodb::aql::AstNode const* node,
arangodb::aql::Variable const* reference, arangodb::aql::Variable const* reference,
size_t itemsInIndex) const override; size_t itemsInIndex) const override;
std::unique_ptr<IndexIterator> iteratorForCondition(transaction::Methods* trx, std::unique_ptr<IndexIterator> iteratorForCondition(transaction::Methods* trx,
arangodb::aql::AstNode const* node, arangodb::aql::AstNode const* node,

View File

@ -669,16 +669,16 @@ std::unique_ptr<MMFilesPersistentIndexIterator> MMFilesPersistentIndex::lookup(t
reverse, leftBorder, rightBorder); reverse, leftBorder, rightBorder);
} }
Index::UsageCosts MMFilesPersistentIndex::supportsFilterCondition( Index::FilterCosts MMFilesPersistentIndex::supportsFilterCondition(
std::vector<std::shared_ptr<arangodb::Index>> const& allIndexes, std::vector<std::shared_ptr<arangodb::Index>> const& allIndexes,
arangodb::aql::AstNode const* node, arangodb::aql::Variable const* reference, arangodb::aql::AstNode const* node, arangodb::aql::Variable const* reference,
size_t itemsInIndex) const { size_t itemsInIndex) const {
return SortedIndexAttributeMatcher::supportsFilterCondition(allIndexes, this, node, reference, itemsInIndex); return SortedIndexAttributeMatcher::supportsFilterCondition(allIndexes, this, node, reference, itemsInIndex);
} }
Index::UsageCosts MMFilesPersistentIndex::supportsSortCondition(arangodb::aql::SortCondition const* sortCondition, Index::SortCosts MMFilesPersistentIndex::supportsSortCondition(arangodb::aql::SortCondition const* sortCondition,
arangodb::aql::Variable const* reference, arangodb::aql::Variable const* reference,
size_t itemsInIndex) const { size_t itemsInIndex) const {
return SortedIndexAttributeMatcher::supportsSortCondition(this, sortCondition, reference, itemsInIndex); return SortedIndexAttributeMatcher::supportsSortCondition(this, sortCondition, reference, itemsInIndex);
} }

View File

@ -161,14 +161,14 @@ class MMFilesPersistentIndex final : public MMFilesPathBasedIndex {
arangodb::velocypack::Slice const, arangodb::velocypack::Slice const,
bool reverse) const; bool reverse) const;
Index::UsageCosts supportsFilterCondition(std::vector<std::shared_ptr<arangodb::Index>> const& allIndexes, Index::FilterCosts supportsFilterCondition(std::vector<std::shared_ptr<arangodb::Index>> const& allIndexes,
arangodb::aql::AstNode const* node, arangodb::aql::AstNode const* node,
arangodb::aql::Variable const* reference, arangodb::aql::Variable const* reference,
size_t itemsInIndex) const override; size_t itemsInIndex) const override;
Index::UsageCosts supportsSortCondition(arangodb::aql::SortCondition const* sortCondition, Index::SortCosts supportsSortCondition(arangodb::aql::SortCondition const* sortCondition,
arangodb::aql::Variable const* reference, arangodb::aql::Variable const* reference,
size_t itemsInIndex) const override; size_t itemsInIndex) const override;
std::unique_ptr<IndexIterator> iteratorForCondition(transaction::Methods* trx, std::unique_ptr<IndexIterator> iteratorForCondition(transaction::Methods* trx,
arangodb::aql::AstNode const* node, arangodb::aql::AstNode const* node,

View File

@ -449,7 +449,7 @@ void MMFilesPrimaryIndex::invokeOnAllElementsForRemoval(
} }
/// @brief checks whether the index supports the condition /// @brief checks whether the index supports the condition
Index::UsageCosts MMFilesPrimaryIndex::supportsFilterCondition( Index::FilterCosts MMFilesPrimaryIndex::supportsFilterCondition(
std::vector<std::shared_ptr<arangodb::Index>> const&, std::vector<std::shared_ptr<arangodb::Index>> const&,
arangodb::aql::AstNode const* node, arangodb::aql::Variable const* reference, arangodb::aql::AstNode const* node, arangodb::aql::Variable const* reference,
size_t itemsInIndex) const { size_t itemsInIndex) const {

View File

@ -269,10 +269,10 @@ class MMFilesPrimaryIndex final : public MMFilesIndex {
void invokeOnAllElements(std::function<bool(LocalDocumentId const&)>); void invokeOnAllElements(std::function<bool(LocalDocumentId const&)>);
void invokeOnAllElementsForRemoval(std::function<bool(MMFilesSimpleIndexElement const&)>); void invokeOnAllElementsForRemoval(std::function<bool(MMFilesSimpleIndexElement const&)>);
Index::UsageCosts supportsFilterCondition(std::vector<std::shared_ptr<arangodb::Index>> const& allIndexes, Index::FilterCosts supportsFilterCondition(std::vector<std::shared_ptr<arangodb::Index>> const& allIndexes,
arangodb::aql::AstNode const* node, arangodb::aql::AstNode const* node,
arangodb::aql::Variable const* reference, arangodb::aql::Variable const* reference,
size_t itemsInIndex) const override; size_t itemsInIndex) const override;
std::unique_ptr<IndexIterator> iteratorForCondition(transaction::Methods* trx, std::unique_ptr<IndexIterator> iteratorForCondition(transaction::Methods* trx,
arangodb::aql::AstNode const* node, arangodb::aql::AstNode const* node,

View File

@ -1179,7 +1179,7 @@ std::unique_ptr<IndexIterator> MMFilesSkiplistIndex::iteratorForCondition(
!opts.ascending, builder.release()); !opts.ascending, builder.release());
} }
Index::UsageCosts MMFilesSkiplistIndex::supportsFilterCondition( Index::FilterCosts MMFilesSkiplistIndex::supportsFilterCondition(
std::vector<std::shared_ptr<arangodb::Index>> const& allIndexes, std::vector<std::shared_ptr<arangodb::Index>> const& allIndexes,
arangodb::aql::AstNode const* node, arangodb::aql::Variable const* reference, arangodb::aql::AstNode const* node, arangodb::aql::Variable const* reference,
size_t itemsInIndex) const { size_t itemsInIndex) const {
@ -1188,9 +1188,9 @@ Index::UsageCosts MMFilesSkiplistIndex::supportsFilterCondition(
itemsInIndex); itemsInIndex);
} }
Index::UsageCosts MMFilesSkiplistIndex::supportsSortCondition(arangodb::aql::SortCondition const* sortCondition, Index::SortCosts MMFilesSkiplistIndex::supportsSortCondition(arangodb::aql::SortCondition const* sortCondition,
arangodb::aql::Variable const* reference, arangodb::aql::Variable const* reference,
size_t itemsInIndex) const { size_t itemsInIndex) const {
return SortedIndexAttributeMatcher::supportsSortCondition(this, sortCondition, reference, itemsInIndex); return SortedIndexAttributeMatcher::supportsSortCondition(this, sortCondition, reference, itemsInIndex);
} }

View File

@ -285,14 +285,14 @@ class MMFilesSkiplistIndex : public MMFilesPathBasedIndex {
void unload() override; void unload() override;
Index::UsageCosts supportsFilterCondition(std::vector<std::shared_ptr<arangodb::Index>> const& allIndexes, Index::FilterCosts supportsFilterCondition(std::vector<std::shared_ptr<arangodb::Index>> const& allIndexes,
arangodb::aql::AstNode const* node, arangodb::aql::AstNode const* node,
arangodb::aql::Variable const* reference, arangodb::aql::Variable const* reference,
size_t itemsInIndex) const override; size_t itemsInIndex) const override;
Index::UsageCosts supportsSortCondition(arangodb::aql::SortCondition const* sortCondition, Index::SortCosts supportsSortCondition(arangodb::aql::SortCondition const* sortCondition,
arangodb::aql::Variable const* reference, arangodb::aql::Variable const* reference,
size_t itemsInindex) const override; size_t itemsInindex) const override;
std::unique_ptr<IndexIterator> iteratorForCondition(transaction::Methods* trx, std::unique_ptr<IndexIterator> iteratorForCondition(transaction::Methods* trx,
arangodb::aql::AstNode const* node, arangodb::aql::AstNode const* node,

View File

@ -519,7 +519,7 @@ Result RocksDBEdgeIndex::remove(transaction::Methods& trx, RocksDBMethods* mthd,
} }
/// @brief checks whether the index supports the condition /// @brief checks whether the index supports the condition
Index::UsageCosts RocksDBEdgeIndex::supportsFilterCondition( Index::FilterCosts RocksDBEdgeIndex::supportsFilterCondition(
std::vector<std::shared_ptr<arangodb::Index>> const& allIndexes, std::vector<std::shared_ptr<arangodb::Index>> const& allIndexes,
arangodb::aql::AstNode const* node, arangodb::aql::Variable const* reference, arangodb::aql::AstNode const* node, arangodb::aql::Variable const* reference,
size_t itemsInIndex) const { size_t itemsInIndex) const {

View File

@ -92,10 +92,10 @@ class RocksDBEdgeIndex final : public RocksDBIndex {
void toVelocyPack(VPackBuilder&, std::underlying_type<Index::Serialize>::type) const override; void toVelocyPack(VPackBuilder&, std::underlying_type<Index::Serialize>::type) const override;
Index::UsageCosts supportsFilterCondition(std::vector<std::shared_ptr<arangodb::Index>> const& allIndexes, Index::FilterCosts supportsFilterCondition(std::vector<std::shared_ptr<arangodb::Index>> const& allIndexes,
arangodb::aql::AstNode const* node, arangodb::aql::AstNode const* node,
arangodb::aql::Variable const* reference, arangodb::aql::Variable const* reference,
size_t itemsInIndex) const override; size_t itemsInIndex) const override;
std::unique_ptr<IndexIterator> iteratorForCondition(transaction::Methods* trx, std::unique_ptr<IndexIterator> iteratorForCondition(transaction::Methods* trx,
arangodb::aql::AstNode const* node, arangodb::aql::AstNode const* node,

View File

@ -669,7 +669,7 @@ Result RocksDBPrimaryIndex::remove(transaction::Methods& trx, RocksDBMethods* mt
} }
/// @brief checks whether the index supports the condition /// @brief checks whether the index supports the condition
Index::UsageCosts RocksDBPrimaryIndex::supportsFilterCondition( Index::FilterCosts RocksDBPrimaryIndex::supportsFilterCondition(
std::vector<std::shared_ptr<arangodb::Index>> const& allIndexes, std::vector<std::shared_ptr<arangodb::Index>> const& allIndexes,
arangodb::aql::AstNode const* node, arangodb::aql::Variable const* reference, arangodb::aql::AstNode const* node, arangodb::aql::Variable const* reference,
size_t itemsInIndex) const { size_t itemsInIndex) const {
@ -681,16 +681,19 @@ Index::UsageCosts RocksDBPrimaryIndex::supportsFilterCondition(
values, nonNullAttributes, values, nonNullAttributes,
/*skip evaluation (during execution)*/ false); /*skip evaluation (during execution)*/ false);
Index::UsageCosts costs; Index::FilterCosts costs = Index::FilterCosts::defaultCosts(itemsInIndex);
costs.estimatedItems = values; if (!found.empty()) {
// TODO: estimatedCost?? costs.supportsCondition = true;
costs.supportsCondition = !found.empty(); costs.coveredAttributes = 1; // always a single attribute
costs.estimatedItems = values;
costs.estimatedCosts = static_cast<double>(values);
}
return costs; return costs;
} }
Index::UsageCosts RocksDBPrimaryIndex::supportsSortCondition(arangodb::aql::SortCondition const* sortCondition, Index::SortCosts RocksDBPrimaryIndex::supportsSortCondition(arangodb::aql::SortCondition const* sortCondition,
arangodb::aql::Variable const* reference, arangodb::aql::Variable const* reference,
size_t itemsInIndex) const { size_t itemsInIndex) const {
return SortedIndexAttributeMatcher::supportsSortCondition(this, sortCondition, reference, itemsInIndex); return SortedIndexAttributeMatcher::supportsSortCondition(this, sortCondition, reference, itemsInIndex);
} }

View File

@ -90,14 +90,14 @@ class RocksDBPrimaryIndex final : public RocksDBIndex {
bool lookupRevision(transaction::Methods* trx, arangodb::velocypack::StringRef key, bool lookupRevision(transaction::Methods* trx, arangodb::velocypack::StringRef key,
LocalDocumentId& id, TRI_voc_rid_t& revisionId) const; LocalDocumentId& id, TRI_voc_rid_t& revisionId) const;
Index::UsageCosts supportsFilterCondition(std::vector<std::shared_ptr<arangodb::Index>> const& allIndexes, Index::FilterCosts supportsFilterCondition(std::vector<std::shared_ptr<arangodb::Index>> const& allIndexes,
arangodb::aql::AstNode const* node, arangodb::aql::AstNode const* node,
arangodb::aql::Variable const* reference, arangodb::aql::Variable const* reference,
size_t itemsInIndex) const override; size_t itemsInIndex) const override;
Index::UsageCosts supportsSortCondition(arangodb::aql::SortCondition const* node, Index::SortCosts supportsSortCondition(arangodb::aql::SortCondition const* node,
arangodb::aql::Variable const* reference, arangodb::aql::Variable const* reference,
size_t itemsInIndex) const override; size_t itemsInIndex) const override;
std::unique_ptr<IndexIterator> iteratorForCondition(transaction::Methods* trx, std::unique_ptr<IndexIterator> iteratorForCondition(transaction::Methods* trx,
arangodb::aql::AstNode const* node, arangodb::aql::AstNode const* node,

View File

@ -1030,16 +1030,16 @@ std::unique_ptr<IndexIterator> RocksDBVPackIndex::lookup(transaction::Methods* t
return std::make_unique<RocksDBVPackIndexIterator>(&_collection, trx, this, reverse, std::move(bounds)); return std::make_unique<RocksDBVPackIndexIterator>(&_collection, trx, this, reverse, std::move(bounds));
} }
Index::UsageCosts RocksDBVPackIndex::supportsFilterCondition( Index::FilterCosts RocksDBVPackIndex::supportsFilterCondition(
std::vector<std::shared_ptr<arangodb::Index>> const& allIndexes, std::vector<std::shared_ptr<arangodb::Index>> const& allIndexes,
arangodb::aql::AstNode const* node, arangodb::aql::Variable const* reference, arangodb::aql::AstNode const* node, arangodb::aql::Variable const* reference,
size_t itemsInIndex) const { size_t itemsInIndex) const {
return SortedIndexAttributeMatcher::supportsFilterCondition(allIndexes, this, node, reference, itemsInIndex); return SortedIndexAttributeMatcher::supportsFilterCondition(allIndexes, this, node, reference, itemsInIndex);
} }
Index::UsageCosts RocksDBVPackIndex::supportsSortCondition(arangodb::aql::SortCondition const* sortCondition, Index::SortCosts RocksDBVPackIndex::supportsSortCondition(arangodb::aql::SortCondition const* sortCondition,
arangodb::aql::Variable const* reference, arangodb::aql::Variable const* reference,
size_t itemsInIndex) const { size_t itemsInIndex) const {
return SortedIndexAttributeMatcher::supportsSortCondition(this, sortCondition, reference, itemsInIndex); return SortedIndexAttributeMatcher::supportsSortCondition(this, sortCondition, reference, itemsInIndex);
} }

View File

@ -97,14 +97,14 @@ class RocksDBVPackIndex : public RocksDBIndex {
std::unique_ptr<IndexIterator> lookup(transaction::Methods*, std::unique_ptr<IndexIterator> lookup(transaction::Methods*,
arangodb::velocypack::Slice const, bool reverse) const; arangodb::velocypack::Slice const, bool reverse) const;
Index::UsageCosts supportsFilterCondition(std::vector<std::shared_ptr<arangodb::Index>> const& allIndexes, Index::FilterCosts supportsFilterCondition(std::vector<std::shared_ptr<arangodb::Index>> const& allIndexes,
arangodb::aql::AstNode const* node, arangodb::aql::AstNode const* node,
arangodb::aql::Variable const* reference, arangodb::aql::Variable const* reference,
size_t itemsInIndex) const override; size_t itemsInIndex) const override;
Index::UsageCosts supportsSortCondition(arangodb::aql::SortCondition const* sortCondition, Index::SortCosts supportsSortCondition(arangodb::aql::SortCondition const* sortCondition,
arangodb::aql::Variable const* reference, arangodb::aql::Variable const* reference,
size_t itemsInIndex) const override; size_t itemsInIndex) const override;
arangodb::aql::AstNode* specializeCondition(arangodb::aql::AstNode* node, arangodb::aql::AstNode* specializeCondition(arangodb::aql::AstNode* node,
arangodb::aql::Variable const* reference) const override; arangodb::aql::Variable const* reference) const override;

View File

@ -568,12 +568,13 @@ std::pair<bool, bool> transaction::Methods::findIndexHandleForAndNode(
double filterCost = 0.0; double filterCost = 0.0;
double sortCost = 0.0; double sortCost = 0.0;
size_t itemsInIndex = itemsInCollection; size_t itemsInIndex = itemsInCollection;
size_t coveredAttributes = 0;
bool supportsFilter = false; bool supportsFilter = false;
bool supportsSort = false; bool supportsSort = false;
// check if the index supports the filter condition // check if the index supports the filter condition
Index::UsageCosts costs = idx->supportsFilterCondition(indexes, node, reference, itemsInIndex); Index::FilterCosts costs = idx->supportsFilterCondition(indexes, node, reference, itemsInIndex);
if (costs.supportsCondition) { if (costs.supportsCondition) {
// index supports the filter condition // index supports the filter condition
@ -594,12 +595,12 @@ std::pair<bool, bool> transaction::Methods::findIndexHandleForAndNode(
// general be supported by an index. for this, a sort condition must not // general be supported by an index. for this, a sort condition must not
// be empty, must consist only of attribute access, and all attributes // be empty, must consist only of attribute access, and all attributes
// must be sorted in the direction // must be sorted in the direction
Index::UsageCosts costs = idx->supportsSortCondition(sortCondition, reference, itemsInIndex); Index::SortCosts costs = idx->supportsSortCondition(sortCondition, reference, itemsInIndex);
if (costs.supportsCondition) { if (costs.supportsCondition) {
supportsSort = true; supportsSort = true;
} }
sortCost = costs.estimatedCosts; sortCost = costs.estimatedCosts;
// TODO: fill coveredAttributes so we don't need to determine it later on coveredAttributes = costs.coveredAttributes;
} }
if (!supportsSort && isOnlyAttributeAccess && node->isOnlyEqualityMatch()) { if (!supportsSort && isOnlyAttributeAccess && node->isOnlyEqualityMatch()) {
@ -607,9 +608,7 @@ std::pair<bool, bool> transaction::Methods::findIndexHandleForAndNode(
// only of equality lookups (==) // only of equality lookups (==)
// now check if the index fields are the same as the sort condition fields // now check if the index fields are the same as the sort condition fields
// e.g. FILTER c.value1 == 1 && c.value2 == 42 SORT c.value1, c.value2 // e.g. FILTER c.value1 == 1 && c.value2 == 42 SORT c.value1, c.value2
size_t coveredFields = sortCondition->coveredAttributes(reference, idx->fields()); if (coveredAttributes == sortCondition->numAttributes() &&
if (coveredFields == sortCondition->numAttributes() &&
(idx->isSorted() || idx->fields().size() == sortCondition->numAttributes())) { (idx->isSorted() || idx->fields().size() == sortCondition->numAttributes())) {
// no sorting needed // no sorting needed
sortCost = 0.0; sortCost = 0.0;
@ -627,7 +626,7 @@ std::pair<bool, bool> transaction::Methods::findIndexHandleForAndNode(
if (supportsSort) { if (supportsSort) {
totalCost += sortCost; totalCost += sortCost;
} else { } else {
totalCost += Index::UsageCosts::defaultsForSorting(itemsInIndex, idx->isPersistent()).estimatedCosts; totalCost += Index::SortCosts::defaultCosts(itemsInIndex, idx->isPersistent()).estimatedCosts;
} }
} }
@ -703,7 +702,7 @@ bool transaction::Methods::findIndexHandleForAndNode(
auto considerIndex = [&bestIndex, &bestCost, itemsInCollection, &indexes, &node, auto considerIndex = [&bestIndex, &bestCost, itemsInCollection, &indexes, &node,
reference](std::shared_ptr<Index> const& idx) -> void { reference](std::shared_ptr<Index> const& idx) -> void {
// check if the index supports the filter expression // check if the index supports the filter expression
Index::UsageCosts costs = idx->supportsFilterCondition(indexes, node, reference, itemsInCollection); Index::FilterCosts costs = idx->supportsFilterCondition(indexes, node, reference, itemsInCollection);
// enable the following line to see index candidates considered with their // enable the following line to see index candidates considered with their
// abilities and scores // abilities and scores
@ -2938,7 +2937,7 @@ bool transaction::Methods::getIndexForSortCondition(
auto considerIndex = [reference, sortCondition, itemsInIndex, &bestCost, &bestIndex, auto considerIndex = [reference, sortCondition, itemsInIndex, &bestCost, &bestIndex,
&coveredAttributes](std::shared_ptr<Index> const& idx) -> void { &coveredAttributes](std::shared_ptr<Index> const& idx) -> void {
Index::UsageCosts costs = idx->supportsSortCondition(sortCondition, reference, itemsInIndex); Index::SortCosts costs = idx->supportsSortCondition(sortCondition, reference, itemsInIndex);
if (costs.supportsCondition && if (costs.supportsCondition &&
(bestIndex == nullptr || costs.estimatedCosts < bestCost)) { (bestIndex == nullptr || costs.estimatedCosts < bestCost)) {
bestCost = costs.estimatedCosts; bestCost = costs.estimatedCosts;

View File

@ -248,10 +248,10 @@ class EdgeIndexMock final : public arangodb::Index {
return {}; // ok return {}; // ok
} }
Index::UsageCosts supportsFilterCondition(std::vector<std::shared_ptr<arangodb::Index>> const& /*allIndexes*/, Index::FilterCosts supportsFilterCondition(std::vector<std::shared_ptr<arangodb::Index>> const& /*allIndexes*/,
arangodb::aql::AstNode const* node, arangodb::aql::AstNode const* node,
arangodb::aql::Variable const* reference, arangodb::aql::Variable const* reference,
size_t itemsInIndex) const override { size_t itemsInIndex) const override {
arangodb::SimpleAttributeEqualityMatcher matcher(IndexAttributes); arangodb::SimpleAttributeEqualityMatcher matcher(IndexAttributes);
return matcher.matchOne(this, node, reference, itemsInIndex); return matcher.matchOne(this, node, reference, itemsInIndex);
} }