1
0
Fork 0

take over selectivity estimates (#6512)

This commit is contained in:
Jan 2018-09-17 16:42:24 +02:00 committed by GitHub
parent 292b6312ae
commit 46b4e7b440
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
27 changed files with 150 additions and 181 deletions

View File

@ -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);
}

View File

@ -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;

View File

@ -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 {

View File

@ -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;

View File

@ -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(

View File

@ -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,

View File

@ -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;

View File

@ -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;
}

View File

@ -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,

View File

@ -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 {

View File

@ -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;

View File

@ -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 {

View File

@ -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;

View File

@ -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);
}

View File

@ -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;

View File

@ -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 {

View File

@ -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;

View File

@ -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);
}

View File

@ -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;

View File

@ -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 {

View File

@ -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;

View File

@ -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 {

View File

@ -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;

View File

@ -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(

View File

@ -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;

View File

@ -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);
}

View File

@ -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,