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();
for (size_t i = 0; i < _indexes.size(); ++i) {
arangodb::aql::AstNode const* condition;
if (root == nullptr || root->numMembers() <= i) {
condition = nullptr;
} else {
condition = root->getMember(i);
}
Index::FilterCosts costs = Index::FilterCosts::defaultCosts(itemsInCollection);
Index::UsageCosts costs;
if (condition != nullptr) {
if (root != nullptr && root->numMembers() > i) {
arangodb::aql::AstNode const* condition = root->getMember(i);
costs = _indexes[i].getIndex()->supportsFilterCondition(std::vector<std::shared_ptr<Index>>(), condition, _outVariable, itemsInCollection);
} else {
costs = Index::UsageCosts::defaultsForFiltering(itemsInCollection);
}
totalItems += costs.estimatedItems;

View File

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

View File

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

View File

@ -178,6 +178,45 @@ std::string defaultIndexName(VPackSlice const& slice) {
} // 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
// logical collection because it could be gone!
@ -630,20 +669,20 @@ Result Index::drop() {
}
/// @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::Variable const* /* reference */,
size_t itemsInIndex) const {
// by default, no filter conditions are supported
return Index::UsageCosts::defaultsForFiltering(itemsInIndex);
// by default no filter conditions are supported
return Index::FilterCosts::defaultCosts(itemsInIndex);
}
/// @brief default implementation for supportsSortCondition
Index::UsageCosts Index::supportsSortCondition(arangodb::aql::SortCondition const* /* sortCondition */,
arangodb::aql::Variable const* /* node */,
size_t itemsInIndex) const {
// by default, no sort conditions are supported
return Index::UsageCosts::defaultsForSorting(itemsInIndex, this->isPersistent());
Index::SortCosts Index::supportsSortCondition(arangodb::aql::SortCondition const* /* sortCondition */,
arangodb::aql::Variable const* /* node */,
size_t itemsInIndex) const {
// by default no sort conditions are supported
return Index::SortCosts::defaultCosts(itemsInIndex, this->isPersistent());
}
arangodb::aql::AstNode* Index::specializeCondition(arangodb::aql::AstNode* /* node */,

View File

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

View File

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

View File

@ -45,17 +45,17 @@ class SimpleAttributeEqualityMatcher {
public:
/// @brief match a single of the attributes
/// this is used for the primary index and the edge index
Index::UsageCosts matchOne(arangodb::Index const* index,
arangodb::aql::AstNode const* node,
arangodb::aql::Variable const* reference,
size_t itemsInIndex);
Index::FilterCosts matchOne(arangodb::Index const* index,
arangodb::aql::AstNode const* node,
arangodb::aql::Variable const* reference,
size_t itemsInIndex);
/// @brief match all of the attributes, in any order
/// this is used for the hash index
Index::UsageCosts matchAll(arangodb::Index const* index,
arangodb::aql::AstNode const* node,
arangodb::aql::Variable const* reference,
size_t itemsInIndex);
Index::FilterCosts matchAll(arangodb::Index const* index,
arangodb::aql::AstNode const* node,
arangodb::aql::Variable const* reference,
size_t itemsInIndex);
/// @brief get the condition parts that the index is responsible for
/// this is used for the primary index and the edge index
@ -84,8 +84,9 @@ class SimpleAttributeEqualityMatcher {
/// that will return in average
/// cost values have no special meaning, except that multiple cost values are
/// comparable, and lower values mean lower costs
Index::UsageCosts calculateIndexCosts(arangodb::Index const* index,
arangodb::aql::AstNode const* attribute, size_t itemsInIndex) const;
Index::FilterCosts calculateIndexCosts(arangodb::Index const* index,
arangodb::aql::AstNode const* attribute,
size_t itemsInIndex, size_t coveredAttributes) const;
/// @brief whether or not the access fits
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,
arangodb::Index const* idx, arangodb::aql::AstNode const* node,
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_set<std::string> nonNullAttributes;
size_t values = 0;
@ -209,7 +207,7 @@ Index::UsageCosts SortedIndexAttributeMatcher::supportsFilterCondition(
size_t attributesCovered = 0;
size_t attributesCoveredByEquality = 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) {
auto it = found.find(i);
@ -238,7 +236,7 @@ Index::UsageCosts SortedIndexAttributeMatcher::supportsFilterCondition(
++attributesCovered;
if (containsEquality) {
++attributesCoveredByEquality;
costs.estimatedCosts /= equalityReductionFactor;
estimatedCosts /= equalityReductionFactor;
// decrease the effect of the equality reduction factor
equalityReductionFactor *= 0.25;
@ -251,10 +249,10 @@ Index::UsageCosts SortedIndexAttributeMatcher::supportsFilterCondition(
if (nodes.size() >= 2) {
// at least two (non-equality) conditions. probably a range with lower
// and upper bound defined
costs.estimatedCosts /= 7.5;
estimatedCosts /= 7.5;
} else {
// one (non-equality). this is either a lower or a higher bound
costs.estimatedCosts /= 2.0;
estimatedCosts /= 2.0;
}
}
@ -265,25 +263,26 @@ Index::UsageCosts SortedIndexAttributeMatcher::supportsFilterCondition(
values = 1;
}
Index::FilterCosts costs = Index::FilterCosts::defaultCosts(itemsInIndex);
costs.coveredAttributes = attributesCovered;
if (attributesCoveredByEquality == idx->fields().size() &&
(idx->unique() || idx->implicitlyUnique())) {
// index is unique and condition covers all attributes by equality
costs.coveredAttributes = attributesCovered;
costs.supportsCondition = true;
if (itemsInIndex == 0) {
costs.estimatedItems = 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;
}
@ -293,8 +292,9 @@ Index::UsageCosts SortedIndexAttributeMatcher::supportsFilterCondition(
// 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
// sparse indexes are contained in Index::canUseConditionPart)
costs.supportsCondition = true;
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
if (idx->hasSelectivityEstimate() &&
@ -357,21 +357,20 @@ Index::UsageCosts SortedIndexAttributeMatcher::supportsFilterCondition(
// slightly prefer indexes that cover more attributes
costs.estimatedCosts -= (attributesCovered - 1) * 0.02;
}
costs.coveredAttributes = attributesCovered;
costs.supportsCondition = true;
return costs;
}
// 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::aql::Variable const* reference, size_t itemsInIndex) {
TRI_ASSERT(sortCondition != nullptr);
Index::UsageCosts costs;
Index::SortCosts costs = Index::SortCosts::defaultCosts(itemsInIndex, idx->isPersistent());
if (!idx->sparse() ||
sortCondition->onlyUsesNonNullSortAttributes(idx->fields())) {
@ -390,7 +389,6 @@ Index::UsageCosts SortedIndexAttributeMatcher::supportsSortCondition(
costs.estimatedCosts *= 4;
}
costs.supportsCondition = true;
return costs;
} else if (costs.coveredAttributes > 0) {
costs.estimatedCosts = (itemsInIndex / costs.coveredAttributes) *
std::log2(static_cast<double>(itemsInIndex));
@ -399,12 +397,11 @@ Index::UsageCosts SortedIndexAttributeMatcher::supportsSortCondition(
costs.estimatedCosts *= 4;
}
costs.supportsCondition = true;
return costs;
}
}
}
return Index::UsageCosts::defaultsForSorting(itemsInIndex, idx->isPersistent());
return costs;
}
/// @brief specializes the condition for use with the index

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -285,14 +285,14 @@ class MMFilesSkiplistIndex : public MMFilesPathBasedIndex {
void unload() override;
Index::UsageCosts supportsFilterCondition(std::vector<std::shared_ptr<arangodb::Index>> const& allIndexes,
arangodb::aql::AstNode const* node,
arangodb::aql::Variable const* reference,
size_t itemsInIndex) const override;
Index::FilterCosts supportsFilterCondition(std::vector<std::shared_ptr<arangodb::Index>> const& allIndexes,
arangodb::aql::AstNode const* node,
arangodb::aql::Variable const* reference,
size_t itemsInIndex) const override;
Index::UsageCosts supportsSortCondition(arangodb::aql::SortCondition const* sortCondition,
arangodb::aql::Variable const* reference,
size_t itemsInindex) const override;
Index::SortCosts supportsSortCondition(arangodb::aql::SortCondition const* sortCondition,
arangodb::aql::Variable const* reference,
size_t itemsInindex) const override;
std::unique_ptr<IndexIterator> iteratorForCondition(transaction::Methods* trx,
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
Index::UsageCosts RocksDBEdgeIndex::supportsFilterCondition(
Index::FilterCosts RocksDBEdgeIndex::supportsFilterCondition(
std::vector<std::shared_ptr<arangodb::Index>> const& allIndexes,
arangodb::aql::AstNode const* node, arangodb::aql::Variable const* reference,
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;
Index::UsageCosts supportsFilterCondition(std::vector<std::shared_ptr<arangodb::Index>> const& allIndexes,
arangodb::aql::AstNode const* node,
arangodb::aql::Variable const* reference,
size_t itemsInIndex) const override;
Index::FilterCosts supportsFilterCondition(std::vector<std::shared_ptr<arangodb::Index>> const& allIndexes,
arangodb::aql::AstNode const* node,
arangodb::aql::Variable const* reference,
size_t itemsInIndex) const override;
std::unique_ptr<IndexIterator> iteratorForCondition(transaction::Methods* trx,
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
Index::UsageCosts RocksDBPrimaryIndex::supportsFilterCondition(
Index::FilterCosts RocksDBPrimaryIndex::supportsFilterCondition(
std::vector<std::shared_ptr<arangodb::Index>> const& allIndexes,
arangodb::aql::AstNode const* node, arangodb::aql::Variable const* reference,
size_t itemsInIndex) const {
@ -681,16 +681,19 @@ Index::UsageCosts RocksDBPrimaryIndex::supportsFilterCondition(
values, nonNullAttributes,
/*skip evaluation (during execution)*/ false);
Index::UsageCosts costs;
costs.estimatedItems = values;
// TODO: estimatedCost??
costs.supportsCondition = !found.empty();
Index::FilterCosts costs = Index::FilterCosts::defaultCosts(itemsInIndex);
if (!found.empty()) {
costs.supportsCondition = true;
costs.coveredAttributes = 1; // always a single attribute
costs.estimatedItems = values;
costs.estimatedCosts = static_cast<double>(values);
}
return costs;
}
Index::UsageCosts RocksDBPrimaryIndex::supportsSortCondition(arangodb::aql::SortCondition const* sortCondition,
arangodb::aql::Variable const* reference,
size_t itemsInIndex) const {
Index::SortCosts RocksDBPrimaryIndex::supportsSortCondition(arangodb::aql::SortCondition const* sortCondition,
arangodb::aql::Variable const* reference,
size_t itemsInIndex) const {
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,
LocalDocumentId& id, TRI_voc_rid_t& revisionId) const;
Index::UsageCosts supportsFilterCondition(std::vector<std::shared_ptr<arangodb::Index>> const& allIndexes,
arangodb::aql::AstNode const* node,
arangodb::aql::Variable const* reference,
size_t itemsInIndex) const override;
Index::FilterCosts supportsFilterCondition(std::vector<std::shared_ptr<arangodb::Index>> const& allIndexes,
arangodb::aql::AstNode const* node,
arangodb::aql::Variable const* reference,
size_t itemsInIndex) const override;
Index::UsageCosts supportsSortCondition(arangodb::aql::SortCondition const* node,
arangodb::aql::Variable const* reference,
size_t itemsInIndex) const override;
Index::SortCosts supportsSortCondition(arangodb::aql::SortCondition const* node,
arangodb::aql::Variable const* reference,
size_t itemsInIndex) const override;
std::unique_ptr<IndexIterator> iteratorForCondition(transaction::Methods* trx,
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));
}
Index::UsageCosts RocksDBVPackIndex::supportsFilterCondition(
Index::FilterCosts RocksDBVPackIndex::supportsFilterCondition(
std::vector<std::shared_ptr<arangodb::Index>> const& allIndexes,
arangodb::aql::AstNode const* node, arangodb::aql::Variable const* reference,
size_t itemsInIndex) const {
return SortedIndexAttributeMatcher::supportsFilterCondition(allIndexes, this, node, reference, itemsInIndex);
}
Index::UsageCosts RocksDBVPackIndex::supportsSortCondition(arangodb::aql::SortCondition const* sortCondition,
arangodb::aql::Variable const* reference,
size_t itemsInIndex) const {
Index::SortCosts RocksDBVPackIndex::supportsSortCondition(arangodb::aql::SortCondition const* sortCondition,
arangodb::aql::Variable const* reference,
size_t itemsInIndex) const {
return SortedIndexAttributeMatcher::supportsSortCondition(this, sortCondition, reference, itemsInIndex);
}

View File

@ -97,14 +97,14 @@ class RocksDBVPackIndex : public RocksDBIndex {
std::unique_ptr<IndexIterator> lookup(transaction::Methods*,
arangodb::velocypack::Slice const, bool reverse) const;
Index::UsageCosts supportsFilterCondition(std::vector<std::shared_ptr<arangodb::Index>> const& allIndexes,
arangodb::aql::AstNode const* node,
arangodb::aql::Variable const* reference,
size_t itemsInIndex) const override;
Index::FilterCosts supportsFilterCondition(std::vector<std::shared_ptr<arangodb::Index>> const& allIndexes,
arangodb::aql::AstNode const* node,
arangodb::aql::Variable const* reference,
size_t itemsInIndex) const override;
Index::UsageCosts supportsSortCondition(arangodb::aql::SortCondition const* sortCondition,
arangodb::aql::Variable const* reference,
size_t itemsInIndex) const override;
Index::SortCosts supportsSortCondition(arangodb::aql::SortCondition const* sortCondition,
arangodb::aql::Variable const* reference,
size_t itemsInIndex) const override;
arangodb::aql::AstNode* specializeCondition(arangodb::aql::AstNode* node,
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 sortCost = 0.0;
size_t itemsInIndex = itemsInCollection;
size_t coveredAttributes = 0;
bool supportsFilter = false;
bool supportsSort = false;
// 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) {
// 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
// be empty, must consist only of attribute access, and all attributes
// 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) {
supportsSort = true;
}
sortCost = costs.estimatedCosts;
// TODO: fill coveredAttributes so we don't need to determine it later on
coveredAttributes = costs.coveredAttributes;
}
if (!supportsSort && isOnlyAttributeAccess && node->isOnlyEqualityMatch()) {
@ -607,9 +608,7 @@ std::pair<bool, bool> transaction::Methods::findIndexHandleForAndNode(
// only of equality lookups (==)
// 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
size_t coveredFields = sortCondition->coveredAttributes(reference, idx->fields());
if (coveredFields == sortCondition->numAttributes() &&
if (coveredAttributes == sortCondition->numAttributes() &&
(idx->isSorted() || idx->fields().size() == sortCondition->numAttributes())) {
// no sorting needed
sortCost = 0.0;
@ -627,7 +626,7 @@ std::pair<bool, bool> transaction::Methods::findIndexHandleForAndNode(
if (supportsSort) {
totalCost += sortCost;
} 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,
reference](std::shared_ptr<Index> const& idx) -> void {
// 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
// abilities and scores
@ -2938,7 +2937,7 @@ bool transaction::Methods::getIndexForSortCondition(
auto considerIndex = [reference, sortCondition, itemsInIndex, &bestCost, &bestIndex,
&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 &&
(bestIndex == nullptr || costs.estimatedCosts < bestCost)) {
bestCost = costs.estimatedCosts;

View File

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