mirror of https://gitee.com/bigwinds/arangodb
take over selectivity estimates (#6512)
This commit is contained in:
parent
292b6312ae
commit
46b4e7b440
|
@ -117,7 +117,7 @@ bool ClusterIndex::hasSelectivityEstimate() const {
|
|||
}
|
||||
|
||||
/// @brief default implementation for selectivityEstimate
|
||||
double ClusterIndex::selectivityEstimate(StringRef const* extra) const {
|
||||
double ClusterIndex::selectivityEstimate(StringRef const&) const {
|
||||
TRI_ASSERT(hasSelectivityEstimate());
|
||||
if (_unique) {
|
||||
return 1.0;
|
||||
|
@ -198,6 +198,7 @@ bool ClusterIndex::matchesDefinition(VPackSlice const& info) const {
|
|||
}
|
||||
|
||||
bool ClusterIndex::supportsFilterCondition(
|
||||
std::vector<std::shared_ptr<arangodb::Index>> const& allIndexes,
|
||||
arangodb::aql::AstNode const* node,
|
||||
arangodb::aql::Variable const* reference, size_t itemsInIndex,
|
||||
size_t& estimatedItems, double& estimatedCost) const {
|
||||
|
@ -216,7 +217,7 @@ bool ClusterIndex::supportsFilterCondition(
|
|||
#endif
|
||||
case TRI_IDX_TYPE_NO_ACCESS_INDEX: {
|
||||
// should not be called for these indexes
|
||||
return Index::supportsFilterCondition(node, reference, itemsInIndex,
|
||||
return Index::supportsFilterCondition(allIndexes, node, reference, itemsInIndex,
|
||||
estimatedItems, estimatedCost);
|
||||
}
|
||||
case TRI_IDX_TYPE_HASH_INDEX:{
|
||||
|
@ -225,7 +226,7 @@ bool ClusterIndex::supportsFilterCondition(
|
|||
return matcher.matchAll(this, node, reference, itemsInIndex, estimatedItems,
|
||||
estimatedCost);
|
||||
} else if (_engineType == ClusterEngineType::RocksDBEngine) {
|
||||
return PersistentIndexAttributeMatcher::supportsFilterCondition(this, node, reference, itemsInIndex,
|
||||
return PersistentIndexAttributeMatcher::supportsFilterCondition(allIndexes, this, node, reference, itemsInIndex,
|
||||
estimatedItems, estimatedCost);
|
||||
}
|
||||
break;
|
||||
|
@ -239,17 +240,17 @@ bool ClusterIndex::supportsFilterCondition(
|
|||
|
||||
case TRI_IDX_TYPE_SKIPLIST_INDEX: {
|
||||
if (_engineType == ClusterEngineType::MMFilesEngine) {
|
||||
return SkiplistIndexAttributeMatcher::supportsFilterCondition(this, node, reference, itemsInIndex,
|
||||
return SkiplistIndexAttributeMatcher::supportsFilterCondition(allIndexes, this, node, reference, itemsInIndex,
|
||||
estimatedItems, estimatedCost);
|
||||
} else if (_engineType == ClusterEngineType::RocksDBEngine) {
|
||||
return PersistentIndexAttributeMatcher::supportsFilterCondition(this, node, reference, itemsInIndex,
|
||||
return PersistentIndexAttributeMatcher::supportsFilterCondition(allIndexes, this, node, reference, itemsInIndex,
|
||||
estimatedItems, estimatedCost);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case TRI_IDX_TYPE_PERSISTENT_INDEX: {
|
||||
// same for both engines
|
||||
return PersistentIndexAttributeMatcher::supportsFilterCondition(this, node, reference, itemsInIndex,
|
||||
return PersistentIndexAttributeMatcher::supportsFilterCondition(allIndexes, this, node, reference, itemsInIndex,
|
||||
estimatedItems, estimatedCost);
|
||||
}
|
||||
|
||||
|
|
|
@ -24,6 +24,7 @@
|
|||
#define ARANGOD_CLUSTER_ENGINE_CLUSTER_INDEX_H 1
|
||||
|
||||
#include "Basics/Common.h"
|
||||
#include "Basics/StringRef.h"
|
||||
#include "ClusterEngine/ClusterTransactionState.h"
|
||||
#include "ClusterEngine/Common.h"
|
||||
#include "Indexes/Index.h"
|
||||
|
@ -66,7 +67,7 @@ class ClusterIndex : public Index {
|
|||
|
||||
bool hasSelectivityEstimate() const override;
|
||||
|
||||
double selectivityEstimate(arangodb::StringRef const* = nullptr) const override;
|
||||
double selectivityEstimate(arangodb::StringRef const& = arangodb::StringRef()) const override;
|
||||
|
||||
/// @brief update the cluster selectivity estimate
|
||||
void updateClusterSelectivityEstimate(double estimate) override;
|
||||
|
@ -83,7 +84,8 @@ class ClusterIndex : public Index {
|
|||
/// @brief Checks if this index is identical to the given definition
|
||||
bool matchesDefinition(arangodb::velocypack::Slice const&) const override;
|
||||
|
||||
bool supportsFilterCondition(arangodb::aql::AstNode const*,
|
||||
bool supportsFilterCondition(std::vector<std::shared_ptr<arangodb::Index>> const& allIndexes,
|
||||
arangodb::aql::AstNode const*,
|
||||
arangodb::aql::Variable const*, size_t, size_t&,
|
||||
double&) const override;
|
||||
|
||||
|
|
|
@ -614,7 +614,7 @@ bool Index::matchesDefinition(VPackSlice const& info) const {
|
|||
}
|
||||
|
||||
/// @brief default implementation for selectivityEstimate
|
||||
double Index::selectivityEstimate(StringRef const* extra) const {
|
||||
double Index::selectivityEstimate(StringRef const&) const {
|
||||
if (_unique) {
|
||||
return 1.0;
|
||||
}
|
||||
|
@ -657,7 +657,8 @@ int Index::sizeHint(transaction::Methods*, size_t) {
|
|||
bool Index::hasBatchInsert() const { return false; }
|
||||
|
||||
/// @brief default implementation for supportsFilterCondition
|
||||
bool Index::supportsFilterCondition(arangodb::aql::AstNode const*,
|
||||
bool Index::supportsFilterCondition(std::vector<std::shared_ptr<arangodb::Index>> const&,
|
||||
arangodb::aql::AstNode const*,
|
||||
arangodb::aql::Variable const*,
|
||||
size_t itemsInIndex, size_t& estimatedItems,
|
||||
double& estimatedCost) const {
|
||||
|
|
|
@ -28,6 +28,7 @@
|
|||
#include "Basics/AttributeNameParser.h"
|
||||
#include "Basics/Exceptions.h"
|
||||
#include "Basics/Result.h"
|
||||
#include "Basics/StringRef.h"
|
||||
#include "VocBase/LocalDocumentId.h"
|
||||
#include "VocBase/voc-types.h"
|
||||
#include "VocBase/vocbase.h"
|
||||
|
@ -42,7 +43,6 @@ class LocalTaskQueue;
|
|||
class IndexIterator;
|
||||
class LogicalCollection;
|
||||
class ManagedDocumentResult;
|
||||
class StringRef;
|
||||
struct IndexIteratorOptions;
|
||||
|
||||
namespace velocypack {
|
||||
|
@ -252,7 +252,7 @@ class Index {
|
|||
/// The extra StringRef is only used in the edge index as direction
|
||||
/// attribute attribute, a Slice would be more flexible.
|
||||
virtual double selectivityEstimate(
|
||||
arangodb::StringRef const* extra = nullptr) const;
|
||||
arangodb::StringRef const& extra = arangodb::StringRef()) const;
|
||||
|
||||
/// @brief update the cluster selectivity estimate
|
||||
virtual void updateClusterSelectivityEstimate(double /*estimate*/) {
|
||||
|
@ -330,7 +330,8 @@ class Index {
|
|||
|
||||
virtual bool hasBatchInsert() const;
|
||||
|
||||
virtual bool supportsFilterCondition(arangodb::aql::AstNode const*,
|
||||
virtual bool supportsFilterCondition(std::vector<std::shared_ptr<arangodb::Index>> const& allIndexes,
|
||||
arangodb::aql::AstNode const*,
|
||||
arangodb::aql::Variable const*, size_t,
|
||||
size_t&, double&) const;
|
||||
|
||||
|
|
|
@ -59,6 +59,7 @@ void PersistentIndexAttributeMatcher::matchAttributes(
|
|||
}
|
||||
|
||||
bool PersistentIndexAttributeMatcher::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,
|
||||
size_t& estimatedItems, double& estimatedCost) {
|
||||
|
@ -68,128 +69,9 @@ bool PersistentIndexAttributeMatcher::supportsFilterCondition(
|
|||
THROW_ARANGO_EXCEPTION(TRI_ERROR_DEBUG);
|
||||
}
|
||||
}
|
||||
|
||||
std::unordered_map<size_t, std::vector<arangodb::aql::AstNode const*>> found;
|
||||
std::unordered_set<std::string> nonNullAttributes;
|
||||
size_t values = 0;
|
||||
matchAttributes(idx, node, reference, found, values, nonNullAttributes,
|
||||
false);
|
||||
|
||||
bool lastContainsEquality = true;
|
||||
size_t attributesCovered = 0;
|
||||
size_t attributesCoveredByEquality = 0;
|
||||
double equalityReductionFactor = 20.0;
|
||||
estimatedCost = static_cast<double>(itemsInIndex);
|
||||
|
||||
for (size_t i = 0; i < idx->fields().size(); ++i) {
|
||||
auto it = found.find(i);
|
||||
|
||||
if (it == found.end()) {
|
||||
// index attribute not covered by condition
|
||||
break;
|
||||
}
|
||||
|
||||
// check if the current condition contains an equality condition
|
||||
auto const& nodes = (*it).second;
|
||||
bool containsEquality = false;
|
||||
for (size_t j = 0; j < nodes.size(); ++j) {
|
||||
if (nodes[j]->type == arangodb::aql::NODE_TYPE_OPERATOR_BINARY_EQ ||
|
||||
nodes[j]->type == arangodb::aql::NODE_TYPE_OPERATOR_BINARY_IN) {
|
||||
containsEquality = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!lastContainsEquality) {
|
||||
// unsupported condition. must abort
|
||||
break;
|
||||
}
|
||||
|
||||
++attributesCovered;
|
||||
if (containsEquality) {
|
||||
++attributesCoveredByEquality;
|
||||
estimatedCost /= equalityReductionFactor;
|
||||
|
||||
// decrease the effect of the equality reduction factor
|
||||
equalityReductionFactor *= 0.25;
|
||||
if (equalityReductionFactor < 2.0) {
|
||||
// equalityReductionFactor shouldn't get too low
|
||||
equalityReductionFactor = 2.0;
|
||||
}
|
||||
} else {
|
||||
// quick estimate for the potential reductions caused by the conditions
|
||||
if (nodes.size() >= 2) {
|
||||
// at least two (non-equality) conditions. probably a range with lower
|
||||
// and upper bound defined
|
||||
estimatedCost /= 7.5;
|
||||
} else {
|
||||
// one (non-equality). this is either a lower or a higher bound
|
||||
estimatedCost /= 2.0;
|
||||
}
|
||||
}
|
||||
|
||||
lastContainsEquality = containsEquality;
|
||||
}
|
||||
|
||||
if (values == 0) {
|
||||
values = 1;
|
||||
}
|
||||
|
||||
if (attributesCoveredByEquality == idx->fields().size() && idx->unique()) {
|
||||
// index is unique and condition covers all attributes by equality
|
||||
if (itemsInIndex == 0) {
|
||||
estimatedItems = 0;
|
||||
estimatedCost = 0.0;
|
||||
return true;
|
||||
}
|
||||
|
||||
estimatedItems = values;
|
||||
estimatedCost = static_cast<double>(estimatedItems * values);
|
||||
// cost is already low... now slightly prioritize unique indexes
|
||||
estimatedCost *= 0.995 - 0.05 * (idx->fields().size() - 1);
|
||||
return true;
|
||||
}
|
||||
|
||||
if (attributesCovered > 0 &&
|
||||
(!idx->sparse() || attributesCovered == idx->fields().size())) {
|
||||
// if the condition contains at least one index attribute and is not
|
||||
// sparse,
|
||||
// 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)
|
||||
estimatedItems = static_cast<size_t>((std::max)(
|
||||
static_cast<size_t>(estimatedCost * values), static_cast<size_t>(1)));
|
||||
|
||||
// check if the index has a selectivity estimate ready
|
||||
if (idx->hasSelectivityEstimate() &&
|
||||
attributesCoveredByEquality == idx->fields().size()) {
|
||||
StringRef ignore;
|
||||
double estimate = idx->selectivityEstimate(&ignore);
|
||||
if (estimate > 0.0) {
|
||||
estimatedItems = static_cast<size_t>(1.0 / estimate);
|
||||
}
|
||||
}
|
||||
if (itemsInIndex == 0) {
|
||||
estimatedCost = 0.0;
|
||||
} else {
|
||||
// simon: neither RocksDBVPackIndex nor MMFilesPersistentIndex have caches
|
||||
/*if (useCache()) {
|
||||
estimatedCost = static_cast<double>(estimatedItems * values) -
|
||||
(_fields.size() - 1) * 0.01;
|
||||
} else {*/
|
||||
estimatedCost =
|
||||
(std::max)(static_cast<double>(1),
|
||||
std::log2(static_cast<double>(itemsInIndex)) * values) -
|
||||
(idx->fields().size() - 1) * 0.01;
|
||||
//}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// index does not help for this condition
|
||||
estimatedItems = itemsInIndex;
|
||||
estimatedCost = static_cast<double>(estimatedItems);
|
||||
return false;
|
||||
|
||||
// just forward to reference implementation
|
||||
return SkiplistIndexAttributeMatcher::supportsFilterCondition(allIndexes, idx, node, reference, itemsInIndex, estimatedItems, estimatedCost);
|
||||
}
|
||||
|
||||
bool PersistentIndexAttributeMatcher::supportsSortCondition(
|
||||
|
|
|
@ -40,7 +40,8 @@ class Index;
|
|||
/// rocksdb based storage
|
||||
namespace PersistentIndexAttributeMatcher {
|
||||
|
||||
bool supportsFilterCondition(arangodb::Index const*,
|
||||
bool supportsFilterCondition(std::vector<std::shared_ptr<arangodb::Index>> const& allIndexes,
|
||||
arangodb::Index const*,
|
||||
arangodb::aql::AstNode const* node,
|
||||
arangodb::aql::Variable const* reference,
|
||||
size_t itemsInIndex, size_t& estimatedItems,
|
||||
|
|
|
@ -323,7 +323,7 @@ void SimpleAttributeEqualityMatcher::calculateIndexCosts(
|
|||
if (attribute != nullptr && attribute->type == aql::NODE_TYPE_ATTRIBUTE_ACCESS) {
|
||||
att = StringRef(attribute->getStringValue(), attribute->getStringLength());
|
||||
}
|
||||
double estimate = index->selectivityEstimate(&att);
|
||||
double estimate = index->selectivityEstimate(att);
|
||||
if (estimate <= 0.0) {
|
||||
// prevent division by zero
|
||||
estimatedItems = itemsInIndex;
|
||||
|
|
|
@ -160,11 +160,16 @@ void SkiplistIndexAttributeMatcher::matchAttributes(
|
|||
case arangodb::aql::NODE_TYPE_OPERATOR_BINARY_IN:
|
||||
if (accessFitsIndex(idx, op->getMember(0), op->getMember(1), op, reference,
|
||||
found, nonNullAttributes, isExecution)) {
|
||||
size_t av = SimpleAttributeEqualityMatcher::estimateNumberOfArrayMembers(op->getMember(1));
|
||||
if (av > 1) {
|
||||
// attr IN [ a, b, c ] => this will produce multiple items, so
|
||||
// count them!
|
||||
values += av - 1;
|
||||
if (op->getMember(1)->isAttributeAccessForVariable(reference, false)) {
|
||||
// 'abc' IN doc.attr[*]
|
||||
++values;
|
||||
} else {
|
||||
size_t av = SimpleAttributeEqualityMatcher::estimateNumberOfArrayMembers(op->getMember(1));
|
||||
if (av > 1) {
|
||||
// attr IN [ a, b, c ] => this will produce multiple items, so
|
||||
// count them!
|
||||
values += av - 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
@ -176,6 +181,7 @@ void SkiplistIndexAttributeMatcher::matchAttributes(
|
|||
}
|
||||
|
||||
bool SkiplistIndexAttributeMatcher::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,
|
||||
size_t& estimatedItems, double& estimatedCost) {
|
||||
|
@ -254,12 +260,10 @@ bool SkiplistIndexAttributeMatcher::supportsFilterCondition(
|
|||
return true;
|
||||
}
|
||||
|
||||
if (estimatedItems >= values) {
|
||||
TRI_ASSERT(itemsInIndex > 0);
|
||||
|
||||
estimatedItems = values;
|
||||
estimatedCost = (std::max)(static_cast<double>(1), std::log2(static_cast<double>(itemsInIndex)) * values);
|
||||
}
|
||||
estimatedItems = values;
|
||||
// ALTERNATIVE: estimatedCost = static_cast<double>(estimatedItems * values);
|
||||
estimatedCost = (std::max)(static_cast<double>(1), std::log2(static_cast<double>(itemsInIndex)) * values);
|
||||
|
||||
// cost is already low... now slightly prioritize unique indexes
|
||||
estimatedCost *= 0.995 - 0.05 * (idx->fields().size() - 1);
|
||||
return true;
|
||||
|
@ -272,11 +276,66 @@ bool SkiplistIndexAttributeMatcher::supportsFilterCondition(
|
|||
// then it can be used (note: additional checks for condition parts in
|
||||
// sparse indexes are contained in Index::canUseConditionPart)
|
||||
estimatedItems = static_cast<size_t>((std::max)(
|
||||
static_cast<size_t>(estimatedCost * values), static_cast<size_t>(1)));
|
||||
static_cast<size_t>(estimatedCost * values), static_cast<size_t>(1)));
|
||||
|
||||
// check if the index has a selectivity estimate ready
|
||||
if (idx->hasSelectivityEstimate() &&
|
||||
attributesCoveredByEquality == idx->fields().size()) {
|
||||
double estimate = idx->selectivityEstimate();
|
||||
if (estimate > 0.0) {
|
||||
estimatedItems = static_cast<size_t>(1.0 / estimate);
|
||||
}
|
||||
} else if (attributesCoveredByEquality > 0) {
|
||||
TRI_ASSERT(attributesCovered > 0);
|
||||
// the index either does not have a selectivity estimate, or not all
|
||||
// of its attributes are covered by the condition using an equality lookup
|
||||
// however, if the search condition uses equality lookups on the prefix
|
||||
// of the index, then we can check if there is another index which is just
|
||||
// indexing the prefix, and "steal" the selectivity estimate from that index
|
||||
// for example, if the condition is "doc.a == 1 && doc.b > 2", and the current
|
||||
// index is created on ["a", "b"], then we will not use the selectivity
|
||||
// estimate of the current index (due to the range condition used for the second
|
||||
// index attribute). however, if there is another index on just "a", we know
|
||||
// that the current index is at least as selective as the index on the single
|
||||
// attribute. and that the extra condition we have will make it even more
|
||||
// selectivity. so in this case we will re-use the selectivity estimate from
|
||||
// the other index, and are happy.
|
||||
for (auto const& otherIdx : allIndexes) {
|
||||
auto const* other = otherIdx.get();
|
||||
if (other == idx || !other->hasSelectivityEstimate()) {
|
||||
continue;
|
||||
}
|
||||
auto const& otherFields = other->fields();
|
||||
if (otherFields.size() >= attributesCovered) {
|
||||
// other index has more fields than we have, or the same amount.
|
||||
// then it will not be helpful
|
||||
continue;
|
||||
}
|
||||
size_t matches = 0;
|
||||
for (size_t i = 0; i < otherFields.size(); ++i) {
|
||||
if (otherFields[i] != idx->fields()[i]) {
|
||||
break;
|
||||
}
|
||||
++matches;
|
||||
}
|
||||
if (matches == otherFields.size()) {
|
||||
double estimate = other->selectivityEstimate();
|
||||
if (estimate > 0.0) {
|
||||
// reuse the estimate from the other index
|
||||
estimatedItems = static_cast<size_t>(1.0 / estimate);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (itemsInIndex == 0) {
|
||||
estimatedCost = 0.0;
|
||||
} else {
|
||||
// lookup cost is O(log(n))
|
||||
estimatedCost = (std::max)(static_cast<double>(1), std::log2(static_cast<double>(itemsInIndex)) * values);
|
||||
// slightly prefer indexes that cover more attributes
|
||||
estimatedCost -= (idx->fields().size() - 1) * 0.01;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -38,7 +38,8 @@ class Index;
|
|||
/// Contains code for in-memory skiplist indexes (MMFilesSkiplistIndex)
|
||||
namespace SkiplistIndexAttributeMatcher {
|
||||
|
||||
bool supportsFilterCondition(arangodb::Index const*,
|
||||
bool 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, size_t& estimatedItems,
|
||||
|
|
|
@ -206,7 +206,7 @@ MMFilesEdgeIndex::MMFilesEdgeIndex(
|
|||
|
||||
/// @brief return a selectivity estimate for the index
|
||||
double MMFilesEdgeIndex::selectivityEstimate(
|
||||
arangodb::StringRef const* attribute) const {
|
||||
arangodb::StringRef const& attribute) const {
|
||||
TRI_ASSERT(!ServerState::instance()->isCoordinator());
|
||||
if (_unique) {
|
||||
return 1.0;
|
||||
|
@ -216,14 +216,14 @@ double MMFilesEdgeIndex::selectivityEstimate(
|
|||
return 0.1;
|
||||
}
|
||||
|
||||
if (attribute != nullptr) {
|
||||
if (!attribute.empty()) {
|
||||
// the index attribute is given here
|
||||
// now check if we can restrict the selectivity estimation to the correct
|
||||
// part of the index
|
||||
if (attribute->compare(StaticStrings::FromString) == 0) {
|
||||
if (attribute.compare(StaticStrings::FromString) == 0) {
|
||||
// _from
|
||||
return _edgesFrom->selectivity();
|
||||
} else if (attribute->compare(StaticStrings::ToString) == 0) {
|
||||
} else if (attribute.compare(StaticStrings::ToString) == 0) {
|
||||
// _to
|
||||
return _edgesTo->selectivity();
|
||||
}
|
||||
|
@ -408,6 +408,7 @@ int MMFilesEdgeIndex::sizeHint(transaction::Methods* trx, size_t size) {
|
|||
|
||||
/// @brief checks whether the index supports the condition
|
||||
bool MMFilesEdgeIndex::supportsFilterCondition(
|
||||
std::vector<std::shared_ptr<arangodb::Index>> const&,
|
||||
arangodb::aql::AstNode const* node,
|
||||
arangodb::aql::Variable const* reference, size_t itemsInIndex,
|
||||
size_t& estimatedItems, double& estimatedCost) const {
|
||||
|
|
|
@ -158,7 +158,7 @@ class MMFilesEdgeIndex final : public MMFilesIndex {
|
|||
|
||||
bool hasSelectivityEstimate() const override { return true; }
|
||||
|
||||
double selectivityEstimate(arangodb::StringRef const* = nullptr) const override;
|
||||
double selectivityEstimate(arangodb::StringRef const& = arangodb::StringRef()) const override;
|
||||
|
||||
size_t memory() const override;
|
||||
|
||||
|
@ -184,11 +184,12 @@ class MMFilesEdgeIndex final : public MMFilesIndex {
|
|||
|
||||
bool hasBatchInsert() const override { return true; }
|
||||
|
||||
TRI_MMFilesEdgeIndexHash_t* from() { return _edgesFrom.get(); }
|
||||
TRI_MMFilesEdgeIndexHash_t* from() const { return _edgesFrom.get(); }
|
||||
|
||||
TRI_MMFilesEdgeIndexHash_t* to() { return _edgesTo.get(); }
|
||||
TRI_MMFilesEdgeIndexHash_t* to() const { return _edgesTo.get(); }
|
||||
|
||||
bool supportsFilterCondition(arangodb::aql::AstNode const*,
|
||||
bool supportsFilterCondition(std::vector<std::shared_ptr<arangodb::Index>> const& allIndexes,
|
||||
arangodb::aql::AstNode const*,
|
||||
arangodb::aql::Variable const*, size_t, size_t&,
|
||||
double&) const override;
|
||||
|
||||
|
|
|
@ -352,7 +352,7 @@ MMFilesHashIndex::~MMFilesHashIndex() {
|
|||
}
|
||||
|
||||
/// @brief returns a selectivity estimate for the index
|
||||
double MMFilesHashIndex::selectivityEstimate(StringRef const*) const {
|
||||
double MMFilesHashIndex::selectivityEstimate(StringRef const&) const {
|
||||
TRI_ASSERT(!ServerState::instance()->isCoordinator());
|
||||
if (_unique) {
|
||||
return 1.0;
|
||||
|
@ -871,6 +871,7 @@ int MMFilesHashIndex::removeMultiElement(transaction::Methods* trx,
|
|||
|
||||
/// @brief checks whether the index supports the condition
|
||||
bool MMFilesHashIndex::supportsFilterCondition(
|
||||
std::vector<std::shared_ptr<arangodb::Index>> const&,
|
||||
arangodb::aql::AstNode const* node,
|
||||
arangodb::aql::Variable const* reference, size_t itemsInIndex,
|
||||
size_t& estimatedItems, double& estimatedCost) const {
|
||||
|
|
|
@ -253,7 +253,7 @@ class MMFilesHashIndex final : public MMFilesPathBasedIndex {
|
|||
|
||||
bool hasSelectivityEstimate() const override { return true; }
|
||||
|
||||
double selectivityEstimate(arangodb::StringRef const* = nullptr) const override;
|
||||
double selectivityEstimate(arangodb::StringRef const& = arangodb::StringRef()) const override;
|
||||
|
||||
size_t memory() const override;
|
||||
|
||||
|
@ -280,7 +280,8 @@ class MMFilesHashIndex final : public MMFilesPathBasedIndex {
|
|||
|
||||
bool hasBatchInsert() const override { return true; }
|
||||
|
||||
bool supportsFilterCondition(arangodb::aql::AstNode const*,
|
||||
bool supportsFilterCondition(std::vector<std::shared_ptr<arangodb::Index>> const& allIndexes,
|
||||
arangodb::aql::AstNode const*,
|
||||
arangodb::aql::Variable const*, size_t, size_t&,
|
||||
double&) const override;
|
||||
|
||||
|
|
|
@ -683,10 +683,11 @@ MMFilesPersistentIndexIterator* MMFilesPersistentIndex::lookup(
|
|||
}
|
||||
|
||||
bool MMFilesPersistentIndex::supportsFilterCondition(
|
||||
std::vector<std::shared_ptr<arangodb::Index>> const& allIndexes,
|
||||
arangodb::aql::AstNode const* node,
|
||||
arangodb::aql::Variable const* reference, size_t itemsInIndex,
|
||||
size_t& estimatedItems, double& estimatedCost) const {
|
||||
return PersistentIndexAttributeMatcher::supportsFilterCondition(this, node, reference,
|
||||
return PersistentIndexAttributeMatcher::supportsFilterCondition(allIndexes, this, node, reference,
|
||||
itemsInIndex, estimatedItems, estimatedCost);
|
||||
}
|
||||
|
||||
|
|
|
@ -181,7 +181,8 @@ class MMFilesPersistentIndex final : public MMFilesPathBasedIndex {
|
|||
arangodb::velocypack::Slice const,
|
||||
bool reverse) const;
|
||||
|
||||
bool supportsFilterCondition(arangodb::aql::AstNode const*,
|
||||
bool supportsFilterCondition(std::vector<std::shared_ptr<arangodb::Index>> const& allIndexes,
|
||||
arangodb::aql::AstNode const*,
|
||||
arangodb::aql::Variable const*, size_t, size_t&,
|
||||
double&) const override;
|
||||
|
||||
|
|
|
@ -450,6 +450,7 @@ void MMFilesPrimaryIndex::invokeOnAllElementsForRemoval(
|
|||
|
||||
/// @brief checks whether the index supports the condition
|
||||
bool MMFilesPrimaryIndex::supportsFilterCondition(
|
||||
std::vector<std::shared_ptr<arangodb::Index>> const&,
|
||||
arangodb::aql::AstNode const* node,
|
||||
arangodb::aql::Variable const* reference, size_t itemsInIndex,
|
||||
size_t& estimatedItems, double& estimatedCost) const {
|
||||
|
|
|
@ -184,7 +184,7 @@ class MMFilesPrimaryIndex final : public MMFilesIndex {
|
|||
|
||||
bool hasSelectivityEstimate() const override { return true; }
|
||||
|
||||
double selectivityEstimate(StringRef const* = nullptr) const override {
|
||||
double selectivityEstimate(StringRef const& = StringRef()) const override {
|
||||
return 1.0;
|
||||
}
|
||||
|
||||
|
@ -261,7 +261,8 @@ class MMFilesPrimaryIndex final : public MMFilesIndex {
|
|||
void invokeOnAllElementsForRemoval(
|
||||
std::function<bool(MMFilesSimpleIndexElement const&)>);
|
||||
|
||||
bool supportsFilterCondition(arangodb::aql::AstNode const*,
|
||||
bool supportsFilterCondition(std::vector<std::shared_ptr<arangodb::Index>> const& allIndexes,
|
||||
arangodb::aql::AstNode const*,
|
||||
arangodb::aql::Variable const*, size_t, size_t&,
|
||||
double&) const override;
|
||||
|
||||
|
|
|
@ -1234,10 +1234,11 @@ IndexIterator* MMFilesSkiplistIndex::iteratorForCondition(
|
|||
}
|
||||
|
||||
bool MMFilesSkiplistIndex::supportsFilterCondition(
|
||||
std::vector<std::shared_ptr<arangodb::Index>> const& allIndexes,
|
||||
arangodb::aql::AstNode const* node,
|
||||
arangodb::aql::Variable const* reference, size_t itemsInIndex,
|
||||
size_t& estimatedItems, double& estimatedCost) const {
|
||||
return SkiplistIndexAttributeMatcher::supportsFilterCondition(this, node, reference, itemsInIndex,
|
||||
return SkiplistIndexAttributeMatcher::supportsFilterCondition(allIndexes, this, node, reference, itemsInIndex,
|
||||
estimatedItems, estimatedCost);
|
||||
}
|
||||
|
||||
|
|
|
@ -299,7 +299,8 @@ class MMFilesSkiplistIndex final : public MMFilesPathBasedIndex {
|
|||
|
||||
void unload() override;
|
||||
|
||||
bool supportsFilterCondition(arangodb::aql::AstNode const*,
|
||||
bool supportsFilterCondition(std::vector<std::shared_ptr<arangodb::Index>> const& allIndexes,
|
||||
arangodb::aql::AstNode const*,
|
||||
arangodb::aql::Variable const*, size_t, size_t&,
|
||||
double&) const override;
|
||||
|
||||
|
|
|
@ -545,12 +545,12 @@ RocksDBEdgeIndex::~RocksDBEdgeIndex() {}
|
|||
|
||||
/// @brief return a selectivity estimate for the index
|
||||
double RocksDBEdgeIndex::selectivityEstimate(
|
||||
arangodb::StringRef const* attribute) const {
|
||||
arangodb::StringRef const& attribute) const {
|
||||
TRI_ASSERT(!ServerState::instance()->isCoordinator());
|
||||
if (_unique) {
|
||||
return 1.0;
|
||||
}
|
||||
if (attribute != nullptr && attribute->compare(_directionAttr)) {
|
||||
if (!attribute.empty() && attribute.compare(_directionAttr)) {
|
||||
return 0.0;
|
||||
}
|
||||
TRI_ASSERT(_estimator != nullptr);
|
||||
|
@ -674,6 +674,7 @@ void RocksDBEdgeIndex::batchInsert(
|
|||
|
||||
/// @brief checks whether the index supports the condition
|
||||
bool RocksDBEdgeIndex::supportsFilterCondition(
|
||||
std::vector<std::shared_ptr<arangodb::Index>> const& allIndexes,
|
||||
arangodb::aql::AstNode const* node,
|
||||
arangodb::aql::Variable const* reference, size_t itemsInIndex,
|
||||
size_t& estimatedItems, double& estimatedCost) const {
|
||||
|
|
|
@ -26,6 +26,7 @@
|
|||
|
||||
#include "Basics/Common.h"
|
||||
#include "Basics/LocalTaskQueue.h"
|
||||
#include "Basics/StringRef.h"
|
||||
#include "Indexes/Index.h"
|
||||
#include "Indexes/IndexIterator.h"
|
||||
#include "RocksDBEngine/RocksDBCuckooIndexEstimator.h"
|
||||
|
@ -137,7 +138,7 @@ class RocksDBEdgeIndex final : public RocksDBIndex {
|
|||
|
||||
bool hasSelectivityEstimate() const override { return true; }
|
||||
|
||||
double selectivityEstimate(arangodb::StringRef const* = nullptr) const override;
|
||||
double selectivityEstimate(arangodb::StringRef const& = arangodb::StringRef()) const override;
|
||||
|
||||
RocksDBCuckooIndexEstimator<uint64_t>* estimator() override;
|
||||
bool needToPersistEstimate() const override;
|
||||
|
@ -152,7 +153,8 @@ class RocksDBEdgeIndex final : public RocksDBIndex {
|
|||
|
||||
bool hasBatchInsert() const override { return false; }
|
||||
|
||||
bool supportsFilterCondition(arangodb::aql::AstNode const*,
|
||||
bool supportsFilterCondition(std::vector<std::shared_ptr<arangodb::Index>> const& allIndexes,
|
||||
arangodb::aql::AstNode const*,
|
||||
arangodb::aql::Variable const*, size_t, size_t&,
|
||||
double&) const override;
|
||||
|
||||
|
|
|
@ -354,6 +354,7 @@ Result RocksDBPrimaryIndex::removeInternal(transaction::Methods* trx,
|
|||
|
||||
/// @brief checks whether the index supports the condition
|
||||
bool RocksDBPrimaryIndex::supportsFilterCondition(
|
||||
std::vector<std::shared_ptr<arangodb::Index>> const& allIndexes,
|
||||
arangodb::aql::AstNode const* node,
|
||||
arangodb::aql::Variable const* reference, size_t itemsInIndex,
|
||||
size_t& estimatedItems, double& estimatedCost) const {
|
||||
|
|
|
@ -24,6 +24,7 @@
|
|||
#ifndef ARANGOD_ROCKSDB_ENGINE_ROCKSDB_PRIMARY_INDEX_H
|
||||
#define ARANGOD_ROCKSDB_ENGINE_ROCKSDB_PRIMARY_INDEX_H 1
|
||||
|
||||
#include "Basics/StringRef.h"
|
||||
#include "Indexes/Index.h"
|
||||
#include "Indexes/IndexIterator.h"
|
||||
#include "RocksDBEngine/RocksDBIndex.h"
|
||||
|
@ -102,7 +103,7 @@ class RocksDBPrimaryIndex final : public RocksDBIndex {
|
|||
|
||||
bool hasSelectivityEstimate() const override { return true; }
|
||||
|
||||
double selectivityEstimate(StringRef const* = nullptr) const override {
|
||||
double selectivityEstimate(StringRef const& = StringRef()) const override {
|
||||
return 1.0;
|
||||
}
|
||||
|
||||
|
@ -127,7 +128,8 @@ class RocksDBPrimaryIndex final : public RocksDBIndex {
|
|||
LocalDocumentId& id,
|
||||
TRI_voc_rid_t& revisionId) const;
|
||||
|
||||
bool supportsFilterCondition(arangodb::aql::AstNode const*,
|
||||
bool supportsFilterCondition(std::vector<std::shared_ptr<arangodb::Index>> const& allIndexes,
|
||||
arangodb::aql::AstNode const*,
|
||||
arangodb::aql::Variable const*, size_t, size_t&,
|
||||
double&) const override;
|
||||
|
||||
|
|
|
@ -299,7 +299,7 @@ RocksDBVPackIndex::RocksDBVPackIndex(
|
|||
RocksDBVPackIndex::~RocksDBVPackIndex() {}
|
||||
|
||||
double RocksDBVPackIndex::selectivityEstimate(
|
||||
arangodb::StringRef const*) const {
|
||||
arangodb::StringRef const&) const {
|
||||
TRI_ASSERT(!ServerState::instance()->isCoordinator());
|
||||
if (_unique) {
|
||||
return 1.0;
|
||||
|
@ -927,11 +927,13 @@ IndexIterator* RocksDBVPackIndex::lookup(transaction::Methods* trx,
|
|||
}
|
||||
|
||||
bool RocksDBVPackIndex::supportsFilterCondition(
|
||||
std::vector<std::shared_ptr<arangodb::Index>> const& allIndexes,
|
||||
arangodb::aql::AstNode const* node,
|
||||
arangodb::aql::Variable const* reference, size_t itemsInIndex,
|
||||
size_t& estimatedItems, double& estimatedCost) const {
|
||||
return PersistentIndexAttributeMatcher::supportsFilterCondition(this, node, reference, itemsInIndex,
|
||||
estimatedItems, estimatedCost);
|
||||
return PersistentIndexAttributeMatcher::supportsFilterCondition(
|
||||
allIndexes, this, node, reference, itemsInIndex,
|
||||
estimatedItems, estimatedCost);
|
||||
}
|
||||
|
||||
bool RocksDBVPackIndex::supportsSortCondition(
|
||||
|
|
|
@ -28,6 +28,7 @@
|
|||
|
||||
#include "Aql/AstNode.h"
|
||||
#include "Basics/Common.h"
|
||||
#include "Basics/StringRef.h"
|
||||
#include "Indexes/IndexIterator.h"
|
||||
#include "RocksDBEngine/RocksDBCuckooIndexEstimator.h"
|
||||
#include "RocksDBEngine/RocksDBIndex.h"
|
||||
|
@ -152,7 +153,7 @@ class RocksDBVPackIndex : public RocksDBIndex {
|
|||
|
||||
bool hasSelectivityEstimate() const override { return true; }
|
||||
|
||||
double selectivityEstimate(arangodb::StringRef const* = nullptr) const override;
|
||||
double selectivityEstimate(arangodb::StringRef const& = arangodb::StringRef()) const override;
|
||||
|
||||
RocksDBCuckooIndexEstimator<uint64_t>* estimator() override;
|
||||
bool needToPersistEstimate() const override;
|
||||
|
@ -182,7 +183,8 @@ class RocksDBVPackIndex : public RocksDBIndex {
|
|||
IndexIterator* lookup(transaction::Methods*,
|
||||
arangodb::velocypack::Slice const, bool reverse) const;
|
||||
|
||||
bool supportsFilterCondition(arangodb::aql::AstNode const*,
|
||||
bool supportsFilterCondition(std::vector<std::shared_ptr<arangodb::Index>> const& allIndexes,
|
||||
arangodb::aql::AstNode const*,
|
||||
arangodb::aql::Variable const*, size_t, size_t&,
|
||||
double&) const override;
|
||||
|
||||
|
|
|
@ -573,7 +573,7 @@ std::pair<bool, bool> transaction::Methods::findIndexHandleForAndNode(
|
|||
// check if the index supports the filter expression
|
||||
double estimatedCost;
|
||||
size_t estimatedItems;
|
||||
if (idx->supportsFilterCondition(node, reference, itemsInIndex,
|
||||
if (idx->supportsFilterCondition(indexes, node, reference, itemsInIndex,
|
||||
estimatedItems, estimatedCost)) {
|
||||
// index supports the filter condition
|
||||
filterCost = estimatedCost;
|
||||
|
@ -661,7 +661,7 @@ bool transaction::Methods::findIndexHandleForAndNode(
|
|||
// check if the index supports the filter expression
|
||||
double estimatedCost;
|
||||
size_t estimatedItems;
|
||||
bool supportsFilter = idx->supportsFilterCondition(node, reference, itemsInIndex,
|
||||
bool supportsFilter = idx->supportsFilterCondition(indexes, node, reference, itemsInIndex,
|
||||
estimatedItems, estimatedCost);
|
||||
|
||||
// enable the following line to see index candidates considered with their
|
||||
|
@ -3001,7 +3001,7 @@ bool transaction::Methods::supportsFilterCondition(
|
|||
"The index id cannot be empty.");
|
||||
}
|
||||
|
||||
return idx->supportsFilterCondition(condition, reference, itemsInIndex,
|
||||
return idx->supportsFilterCondition(std::vector<std::shared_ptr<Index>>(), condition, reference, itemsInIndex,
|
||||
estimatedItems, estimatedCost);
|
||||
}
|
||||
|
||||
|
|
|
@ -263,6 +263,7 @@ class EdgeIndexMock final : public arangodb::Index {
|
|||
}
|
||||
|
||||
bool supportsFilterCondition(
|
||||
std::vector<std::shared_ptr<arangodb::Index>> const& /*allIndexes*/,
|
||||
arangodb::aql::AstNode const* node,
|
||||
arangodb::aql::Variable const* reference,
|
||||
size_t itemsInIndex,
|
||||
|
|
Loading…
Reference in New Issue