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
|
/// @brief default implementation for selectivityEstimate
|
||||||
double ClusterIndex::selectivityEstimate(StringRef const* extra) const {
|
double ClusterIndex::selectivityEstimate(StringRef const&) const {
|
||||||
TRI_ASSERT(hasSelectivityEstimate());
|
TRI_ASSERT(hasSelectivityEstimate());
|
||||||
if (_unique) {
|
if (_unique) {
|
||||||
return 1.0;
|
return 1.0;
|
||||||
|
@ -198,6 +198,7 @@ bool ClusterIndex::matchesDefinition(VPackSlice const& info) const {
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ClusterIndex::supportsFilterCondition(
|
bool ClusterIndex::supportsFilterCondition(
|
||||||
|
std::vector<std::shared_ptr<arangodb::Index>> const& allIndexes,
|
||||||
arangodb::aql::AstNode const* node,
|
arangodb::aql::AstNode const* node,
|
||||||
arangodb::aql::Variable const* reference, size_t itemsInIndex,
|
arangodb::aql::Variable const* reference, size_t itemsInIndex,
|
||||||
size_t& estimatedItems, double& estimatedCost) const {
|
size_t& estimatedItems, double& estimatedCost) const {
|
||||||
|
@ -216,7 +217,7 @@ bool ClusterIndex::supportsFilterCondition(
|
||||||
#endif
|
#endif
|
||||||
case TRI_IDX_TYPE_NO_ACCESS_INDEX: {
|
case TRI_IDX_TYPE_NO_ACCESS_INDEX: {
|
||||||
// should not be called for these indexes
|
// should not be called for these indexes
|
||||||
return Index::supportsFilterCondition(node, reference, itemsInIndex,
|
return Index::supportsFilterCondition(allIndexes, node, reference, itemsInIndex,
|
||||||
estimatedItems, estimatedCost);
|
estimatedItems, estimatedCost);
|
||||||
}
|
}
|
||||||
case TRI_IDX_TYPE_HASH_INDEX:{
|
case TRI_IDX_TYPE_HASH_INDEX:{
|
||||||
|
@ -225,7 +226,7 @@ bool ClusterIndex::supportsFilterCondition(
|
||||||
return matcher.matchAll(this, node, reference, itemsInIndex, estimatedItems,
|
return matcher.matchAll(this, node, reference, itemsInIndex, estimatedItems,
|
||||||
estimatedCost);
|
estimatedCost);
|
||||||
} else if (_engineType == ClusterEngineType::RocksDBEngine) {
|
} else if (_engineType == ClusterEngineType::RocksDBEngine) {
|
||||||
return PersistentIndexAttributeMatcher::supportsFilterCondition(this, node, reference, itemsInIndex,
|
return PersistentIndexAttributeMatcher::supportsFilterCondition(allIndexes, this, node, reference, itemsInIndex,
|
||||||
estimatedItems, estimatedCost);
|
estimatedItems, estimatedCost);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
@ -239,17 +240,17 @@ bool ClusterIndex::supportsFilterCondition(
|
||||||
|
|
||||||
case TRI_IDX_TYPE_SKIPLIST_INDEX: {
|
case TRI_IDX_TYPE_SKIPLIST_INDEX: {
|
||||||
if (_engineType == ClusterEngineType::MMFilesEngine) {
|
if (_engineType == ClusterEngineType::MMFilesEngine) {
|
||||||
return SkiplistIndexAttributeMatcher::supportsFilterCondition(this, node, reference, itemsInIndex,
|
return SkiplistIndexAttributeMatcher::supportsFilterCondition(allIndexes, this, node, reference, itemsInIndex,
|
||||||
estimatedItems, estimatedCost);
|
estimatedItems, estimatedCost);
|
||||||
} else if (_engineType == ClusterEngineType::RocksDBEngine) {
|
} else if (_engineType == ClusterEngineType::RocksDBEngine) {
|
||||||
return PersistentIndexAttributeMatcher::supportsFilterCondition(this, node, reference, itemsInIndex,
|
return PersistentIndexAttributeMatcher::supportsFilterCondition(allIndexes, this, node, reference, itemsInIndex,
|
||||||
estimatedItems, estimatedCost);
|
estimatedItems, estimatedCost);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case TRI_IDX_TYPE_PERSISTENT_INDEX: {
|
case TRI_IDX_TYPE_PERSISTENT_INDEX: {
|
||||||
// same for both engines
|
// same for both engines
|
||||||
return PersistentIndexAttributeMatcher::supportsFilterCondition(this, node, reference, itemsInIndex,
|
return PersistentIndexAttributeMatcher::supportsFilterCondition(allIndexes, this, node, reference, itemsInIndex,
|
||||||
estimatedItems, estimatedCost);
|
estimatedItems, estimatedCost);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -24,6 +24,7 @@
|
||||||
#define ARANGOD_CLUSTER_ENGINE_CLUSTER_INDEX_H 1
|
#define ARANGOD_CLUSTER_ENGINE_CLUSTER_INDEX_H 1
|
||||||
|
|
||||||
#include "Basics/Common.h"
|
#include "Basics/Common.h"
|
||||||
|
#include "Basics/StringRef.h"
|
||||||
#include "ClusterEngine/ClusterTransactionState.h"
|
#include "ClusterEngine/ClusterTransactionState.h"
|
||||||
#include "ClusterEngine/Common.h"
|
#include "ClusterEngine/Common.h"
|
||||||
#include "Indexes/Index.h"
|
#include "Indexes/Index.h"
|
||||||
|
@ -66,7 +67,7 @@ class ClusterIndex : public Index {
|
||||||
|
|
||||||
bool hasSelectivityEstimate() const override;
|
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
|
/// @brief update the cluster selectivity estimate
|
||||||
void updateClusterSelectivityEstimate(double estimate) override;
|
void updateClusterSelectivityEstimate(double estimate) override;
|
||||||
|
@ -83,7 +84,8 @@ class ClusterIndex : public Index {
|
||||||
/// @brief Checks if this index is identical to the given definition
|
/// @brief Checks if this index is identical to the given definition
|
||||||
bool matchesDefinition(arangodb::velocypack::Slice const&) const override;
|
bool matchesDefinition(arangodb::velocypack::Slice const&) const override;
|
||||||
|
|
||||||
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&,
|
arangodb::aql::Variable const*, size_t, size_t&,
|
||||||
double&) const override;
|
double&) const override;
|
||||||
|
|
||||||
|
|
|
@ -614,7 +614,7 @@ bool Index::matchesDefinition(VPackSlice const& info) const {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// @brief default implementation for selectivityEstimate
|
/// @brief default implementation for selectivityEstimate
|
||||||
double Index::selectivityEstimate(StringRef const* extra) const {
|
double Index::selectivityEstimate(StringRef const&) const {
|
||||||
if (_unique) {
|
if (_unique) {
|
||||||
return 1.0;
|
return 1.0;
|
||||||
}
|
}
|
||||||
|
@ -657,7 +657,8 @@ int Index::sizeHint(transaction::Methods*, size_t) {
|
||||||
bool Index::hasBatchInsert() const { return false; }
|
bool Index::hasBatchInsert() const { return false; }
|
||||||
|
|
||||||
/// @brief default implementation for supportsFilterCondition
|
/// @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*,
|
arangodb::aql::Variable const*,
|
||||||
size_t itemsInIndex, size_t& estimatedItems,
|
size_t itemsInIndex, size_t& estimatedItems,
|
||||||
double& estimatedCost) const {
|
double& estimatedCost) const {
|
||||||
|
|
|
@ -28,6 +28,7 @@
|
||||||
#include "Basics/AttributeNameParser.h"
|
#include "Basics/AttributeNameParser.h"
|
||||||
#include "Basics/Exceptions.h"
|
#include "Basics/Exceptions.h"
|
||||||
#include "Basics/Result.h"
|
#include "Basics/Result.h"
|
||||||
|
#include "Basics/StringRef.h"
|
||||||
#include "VocBase/LocalDocumentId.h"
|
#include "VocBase/LocalDocumentId.h"
|
||||||
#include "VocBase/voc-types.h"
|
#include "VocBase/voc-types.h"
|
||||||
#include "VocBase/vocbase.h"
|
#include "VocBase/vocbase.h"
|
||||||
|
@ -42,7 +43,6 @@ class LocalTaskQueue;
|
||||||
class IndexIterator;
|
class IndexIterator;
|
||||||
class LogicalCollection;
|
class LogicalCollection;
|
||||||
class ManagedDocumentResult;
|
class ManagedDocumentResult;
|
||||||
class StringRef;
|
|
||||||
struct IndexIteratorOptions;
|
struct IndexIteratorOptions;
|
||||||
|
|
||||||
namespace velocypack {
|
namespace velocypack {
|
||||||
|
@ -252,7 +252,7 @@ class Index {
|
||||||
/// The extra StringRef is only used in the edge index as direction
|
/// The extra StringRef is only used in the edge index as direction
|
||||||
/// attribute attribute, a Slice would be more flexible.
|
/// attribute attribute, a Slice would be more flexible.
|
||||||
virtual double selectivityEstimate(
|
virtual double selectivityEstimate(
|
||||||
arangodb::StringRef const* extra = nullptr) const;
|
arangodb::StringRef const& extra = arangodb::StringRef()) const;
|
||||||
|
|
||||||
/// @brief update the cluster selectivity estimate
|
/// @brief update the cluster selectivity estimate
|
||||||
virtual void updateClusterSelectivityEstimate(double /*estimate*/) {
|
virtual void updateClusterSelectivityEstimate(double /*estimate*/) {
|
||||||
|
@ -330,7 +330,8 @@ class Index {
|
||||||
|
|
||||||
virtual bool hasBatchInsert() const;
|
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,
|
arangodb::aql::Variable const*, size_t,
|
||||||
size_t&, double&) const;
|
size_t&, double&) const;
|
||||||
|
|
||||||
|
|
|
@ -59,6 +59,7 @@ void PersistentIndexAttributeMatcher::matchAttributes(
|
||||||
}
|
}
|
||||||
|
|
||||||
bool PersistentIndexAttributeMatcher::supportsFilterCondition(
|
bool PersistentIndexAttributeMatcher::supportsFilterCondition(
|
||||||
|
std::vector<std::shared_ptr<arangodb::Index>> const& allIndexes,
|
||||||
arangodb::Index const* idx, arangodb::aql::AstNode const* node,
|
arangodb::Index const* idx, arangodb::aql::AstNode const* node,
|
||||||
arangodb::aql::Variable const* reference, size_t itemsInIndex,
|
arangodb::aql::Variable const* reference, size_t itemsInIndex,
|
||||||
size_t& estimatedItems, double& estimatedCost) {
|
size_t& estimatedItems, double& estimatedCost) {
|
||||||
|
@ -69,127 +70,8 @@ bool PersistentIndexAttributeMatcher::supportsFilterCondition(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
std::unordered_map<size_t, std::vector<arangodb::aql::AstNode const*>> found;
|
// just forward to reference implementation
|
||||||
std::unordered_set<std::string> nonNullAttributes;
|
return SkiplistIndexAttributeMatcher::supportsFilterCondition(allIndexes, idx, node, reference, itemsInIndex, estimatedItems, estimatedCost);
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool PersistentIndexAttributeMatcher::supportsSortCondition(
|
bool PersistentIndexAttributeMatcher::supportsSortCondition(
|
||||||
|
|
|
@ -40,7 +40,8 @@ class Index;
|
||||||
/// rocksdb based storage
|
/// rocksdb based storage
|
||||||
namespace PersistentIndexAttributeMatcher {
|
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::AstNode const* node,
|
||||||
arangodb::aql::Variable const* reference,
|
arangodb::aql::Variable const* reference,
|
||||||
size_t itemsInIndex, size_t& estimatedItems,
|
size_t itemsInIndex, size_t& estimatedItems,
|
||||||
|
|
|
@ -323,7 +323,7 @@ void SimpleAttributeEqualityMatcher::calculateIndexCosts(
|
||||||
if (attribute != nullptr && attribute->type == aql::NODE_TYPE_ATTRIBUTE_ACCESS) {
|
if (attribute != nullptr && attribute->type == aql::NODE_TYPE_ATTRIBUTE_ACCESS) {
|
||||||
att = StringRef(attribute->getStringValue(), attribute->getStringLength());
|
att = StringRef(attribute->getStringValue(), attribute->getStringLength());
|
||||||
}
|
}
|
||||||
double estimate = index->selectivityEstimate(&att);
|
double estimate = index->selectivityEstimate(att);
|
||||||
if (estimate <= 0.0) {
|
if (estimate <= 0.0) {
|
||||||
// prevent division by zero
|
// prevent division by zero
|
||||||
estimatedItems = itemsInIndex;
|
estimatedItems = itemsInIndex;
|
||||||
|
|
|
@ -160,6 +160,10 @@ void SkiplistIndexAttributeMatcher::matchAttributes(
|
||||||
case arangodb::aql::NODE_TYPE_OPERATOR_BINARY_IN:
|
case arangodb::aql::NODE_TYPE_OPERATOR_BINARY_IN:
|
||||||
if (accessFitsIndex(idx, op->getMember(0), op->getMember(1), op, reference,
|
if (accessFitsIndex(idx, op->getMember(0), op->getMember(1), op, reference,
|
||||||
found, nonNullAttributes, isExecution)) {
|
found, nonNullAttributes, isExecution)) {
|
||||||
|
if (op->getMember(1)->isAttributeAccessForVariable(reference, false)) {
|
||||||
|
// 'abc' IN doc.attr[*]
|
||||||
|
++values;
|
||||||
|
} else {
|
||||||
size_t av = SimpleAttributeEqualityMatcher::estimateNumberOfArrayMembers(op->getMember(1));
|
size_t av = SimpleAttributeEqualityMatcher::estimateNumberOfArrayMembers(op->getMember(1));
|
||||||
if (av > 1) {
|
if (av > 1) {
|
||||||
// attr IN [ a, b, c ] => this will produce multiple items, so
|
// attr IN [ a, b, c ] => this will produce multiple items, so
|
||||||
|
@ -167,6 +171,7 @@ void SkiplistIndexAttributeMatcher::matchAttributes(
|
||||||
values += av - 1;
|
values += av - 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
|
@ -176,6 +181,7 @@ void SkiplistIndexAttributeMatcher::matchAttributes(
|
||||||
}
|
}
|
||||||
|
|
||||||
bool SkiplistIndexAttributeMatcher::supportsFilterCondition(
|
bool SkiplistIndexAttributeMatcher::supportsFilterCondition(
|
||||||
|
std::vector<std::shared_ptr<arangodb::Index>> const& allIndexes,
|
||||||
arangodb::Index const* idx, arangodb::aql::AstNode const* node,
|
arangodb::Index const* idx, arangodb::aql::AstNode const* node,
|
||||||
arangodb::aql::Variable const* reference, size_t itemsInIndex,
|
arangodb::aql::Variable const* reference, size_t itemsInIndex,
|
||||||
size_t& estimatedItems, double& estimatedCost) {
|
size_t& estimatedItems, double& estimatedCost) {
|
||||||
|
@ -254,12 +260,10 @@ bool SkiplistIndexAttributeMatcher::supportsFilterCondition(
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (estimatedItems >= values) {
|
|
||||||
TRI_ASSERT(itemsInIndex > 0);
|
|
||||||
|
|
||||||
estimatedItems = values;
|
estimatedItems = values;
|
||||||
|
// ALTERNATIVE: estimatedCost = static_cast<double>(estimatedItems * values);
|
||||||
estimatedCost = (std::max)(static_cast<double>(1), std::log2(static_cast<double>(itemsInIndex)) * values);
|
estimatedCost = (std::max)(static_cast<double>(1), std::log2(static_cast<double>(itemsInIndex)) * values);
|
||||||
}
|
|
||||||
// cost is already low... now slightly prioritize unique indexes
|
// cost is already low... now slightly prioritize unique indexes
|
||||||
estimatedCost *= 0.995 - 0.05 * (idx->fields().size() - 1);
|
estimatedCost *= 0.995 - 0.05 * (idx->fields().size() - 1);
|
||||||
return true;
|
return true;
|
||||||
|
@ -273,10 +277,65 @@ bool SkiplistIndexAttributeMatcher::supportsFilterCondition(
|
||||||
// sparse indexes are contained in Index::canUseConditionPart)
|
// sparse indexes are contained in Index::canUseConditionPart)
|
||||||
estimatedItems = static_cast<size_t>((std::max)(
|
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) {
|
if (itemsInIndex == 0) {
|
||||||
estimatedCost = 0.0;
|
estimatedCost = 0.0;
|
||||||
} else {
|
} else {
|
||||||
|
// lookup cost is O(log(n))
|
||||||
estimatedCost = (std::max)(static_cast<double>(1), std::log2(static_cast<double>(itemsInIndex)) * values);
|
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;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
|
@ -38,7 +38,8 @@ class Index;
|
||||||
/// Contains code for in-memory skiplist indexes (MMFilesSkiplistIndex)
|
/// Contains code for in-memory skiplist indexes (MMFilesSkiplistIndex)
|
||||||
namespace SkiplistIndexAttributeMatcher {
|
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::AstNode const* node,
|
||||||
arangodb::aql::Variable const* reference,
|
arangodb::aql::Variable const* reference,
|
||||||
size_t itemsInIndex, size_t& estimatedItems,
|
size_t itemsInIndex, size_t& estimatedItems,
|
||||||
|
|
|
@ -206,7 +206,7 @@ MMFilesEdgeIndex::MMFilesEdgeIndex(
|
||||||
|
|
||||||
/// @brief return a selectivity estimate for the index
|
/// @brief return a selectivity estimate for the index
|
||||||
double MMFilesEdgeIndex::selectivityEstimate(
|
double MMFilesEdgeIndex::selectivityEstimate(
|
||||||
arangodb::StringRef const* attribute) const {
|
arangodb::StringRef const& attribute) const {
|
||||||
TRI_ASSERT(!ServerState::instance()->isCoordinator());
|
TRI_ASSERT(!ServerState::instance()->isCoordinator());
|
||||||
if (_unique) {
|
if (_unique) {
|
||||||
return 1.0;
|
return 1.0;
|
||||||
|
@ -216,14 +216,14 @@ double MMFilesEdgeIndex::selectivityEstimate(
|
||||||
return 0.1;
|
return 0.1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (attribute != nullptr) {
|
if (!attribute.empty()) {
|
||||||
// the index attribute is given here
|
// the index attribute is given here
|
||||||
// now check if we can restrict the selectivity estimation to the correct
|
// now check if we can restrict the selectivity estimation to the correct
|
||||||
// part of the index
|
// part of the index
|
||||||
if (attribute->compare(StaticStrings::FromString) == 0) {
|
if (attribute.compare(StaticStrings::FromString) == 0) {
|
||||||
// _from
|
// _from
|
||||||
return _edgesFrom->selectivity();
|
return _edgesFrom->selectivity();
|
||||||
} else if (attribute->compare(StaticStrings::ToString) == 0) {
|
} else if (attribute.compare(StaticStrings::ToString) == 0) {
|
||||||
// _to
|
// _to
|
||||||
return _edgesTo->selectivity();
|
return _edgesTo->selectivity();
|
||||||
}
|
}
|
||||||
|
@ -408,6 +408,7 @@ int MMFilesEdgeIndex::sizeHint(transaction::Methods* trx, size_t size) {
|
||||||
|
|
||||||
/// @brief checks whether the index supports the condition
|
/// @brief checks whether the index supports the condition
|
||||||
bool MMFilesEdgeIndex::supportsFilterCondition(
|
bool MMFilesEdgeIndex::supportsFilterCondition(
|
||||||
|
std::vector<std::shared_ptr<arangodb::Index>> const&,
|
||||||
arangodb::aql::AstNode const* node,
|
arangodb::aql::AstNode const* node,
|
||||||
arangodb::aql::Variable const* reference, size_t itemsInIndex,
|
arangodb::aql::Variable const* reference, size_t itemsInIndex,
|
||||||
size_t& estimatedItems, double& estimatedCost) const {
|
size_t& estimatedItems, double& estimatedCost) const {
|
||||||
|
|
|
@ -158,7 +158,7 @@ class MMFilesEdgeIndex final : public MMFilesIndex {
|
||||||
|
|
||||||
bool hasSelectivityEstimate() const override { return true; }
|
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;
|
size_t memory() const override;
|
||||||
|
|
||||||
|
@ -184,11 +184,12 @@ class MMFilesEdgeIndex final : public MMFilesIndex {
|
||||||
|
|
||||||
bool hasBatchInsert() const override { return true; }
|
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&,
|
arangodb::aql::Variable const*, size_t, size_t&,
|
||||||
double&) const override;
|
double&) const override;
|
||||||
|
|
||||||
|
|
|
@ -352,7 +352,7 @@ MMFilesHashIndex::~MMFilesHashIndex() {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// @brief returns a selectivity estimate for the index
|
/// @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());
|
TRI_ASSERT(!ServerState::instance()->isCoordinator());
|
||||||
if (_unique) {
|
if (_unique) {
|
||||||
return 1.0;
|
return 1.0;
|
||||||
|
@ -871,6 +871,7 @@ int MMFilesHashIndex::removeMultiElement(transaction::Methods* trx,
|
||||||
|
|
||||||
/// @brief checks whether the index supports the condition
|
/// @brief checks whether the index supports the condition
|
||||||
bool MMFilesHashIndex::supportsFilterCondition(
|
bool MMFilesHashIndex::supportsFilterCondition(
|
||||||
|
std::vector<std::shared_ptr<arangodb::Index>> const&,
|
||||||
arangodb::aql::AstNode const* node,
|
arangodb::aql::AstNode const* node,
|
||||||
arangodb::aql::Variable const* reference, size_t itemsInIndex,
|
arangodb::aql::Variable const* reference, size_t itemsInIndex,
|
||||||
size_t& estimatedItems, double& estimatedCost) const {
|
size_t& estimatedItems, double& estimatedCost) const {
|
||||||
|
|
|
@ -253,7 +253,7 @@ class MMFilesHashIndex final : public MMFilesPathBasedIndex {
|
||||||
|
|
||||||
bool hasSelectivityEstimate() const override { return true; }
|
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;
|
size_t memory() const override;
|
||||||
|
|
||||||
|
@ -280,7 +280,8 @@ class MMFilesHashIndex final : public MMFilesPathBasedIndex {
|
||||||
|
|
||||||
bool hasBatchInsert() const override { return true; }
|
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&,
|
arangodb::aql::Variable const*, size_t, size_t&,
|
||||||
double&) const override;
|
double&) const override;
|
||||||
|
|
||||||
|
|
|
@ -683,10 +683,11 @@ MMFilesPersistentIndexIterator* MMFilesPersistentIndex::lookup(
|
||||||
}
|
}
|
||||||
|
|
||||||
bool MMFilesPersistentIndex::supportsFilterCondition(
|
bool MMFilesPersistentIndex::supportsFilterCondition(
|
||||||
|
std::vector<std::shared_ptr<arangodb::Index>> const& allIndexes,
|
||||||
arangodb::aql::AstNode const* node,
|
arangodb::aql::AstNode const* node,
|
||||||
arangodb::aql::Variable const* reference, size_t itemsInIndex,
|
arangodb::aql::Variable const* reference, size_t itemsInIndex,
|
||||||
size_t& estimatedItems, double& estimatedCost) const {
|
size_t& estimatedItems, double& estimatedCost) const {
|
||||||
return PersistentIndexAttributeMatcher::supportsFilterCondition(this, node, reference,
|
return PersistentIndexAttributeMatcher::supportsFilterCondition(allIndexes, this, node, reference,
|
||||||
itemsInIndex, estimatedItems, estimatedCost);
|
itemsInIndex, estimatedItems, estimatedCost);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -181,7 +181,8 @@ class MMFilesPersistentIndex final : public MMFilesPathBasedIndex {
|
||||||
arangodb::velocypack::Slice const,
|
arangodb::velocypack::Slice const,
|
||||||
bool reverse) 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&,
|
arangodb::aql::Variable const*, size_t, size_t&,
|
||||||
double&) const override;
|
double&) const override;
|
||||||
|
|
||||||
|
|
|
@ -450,6 +450,7 @@ void MMFilesPrimaryIndex::invokeOnAllElementsForRemoval(
|
||||||
|
|
||||||
/// @brief checks whether the index supports the condition
|
/// @brief checks whether the index supports the condition
|
||||||
bool MMFilesPrimaryIndex::supportsFilterCondition(
|
bool MMFilesPrimaryIndex::supportsFilterCondition(
|
||||||
|
std::vector<std::shared_ptr<arangodb::Index>> const&,
|
||||||
arangodb::aql::AstNode const* node,
|
arangodb::aql::AstNode const* node,
|
||||||
arangodb::aql::Variable const* reference, size_t itemsInIndex,
|
arangodb::aql::Variable const* reference, size_t itemsInIndex,
|
||||||
size_t& estimatedItems, double& estimatedCost) const {
|
size_t& estimatedItems, double& estimatedCost) const {
|
||||||
|
|
|
@ -184,7 +184,7 @@ class MMFilesPrimaryIndex final : public MMFilesIndex {
|
||||||
|
|
||||||
bool hasSelectivityEstimate() const override { return true; }
|
bool hasSelectivityEstimate() const override { return true; }
|
||||||
|
|
||||||
double selectivityEstimate(StringRef const* = nullptr) const override {
|
double selectivityEstimate(StringRef const& = StringRef()) const override {
|
||||||
return 1.0;
|
return 1.0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -261,7 +261,8 @@ class MMFilesPrimaryIndex final : public MMFilesIndex {
|
||||||
void invokeOnAllElementsForRemoval(
|
void invokeOnAllElementsForRemoval(
|
||||||
std::function<bool(MMFilesSimpleIndexElement const&)>);
|
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&,
|
arangodb::aql::Variable const*, size_t, size_t&,
|
||||||
double&) const override;
|
double&) const override;
|
||||||
|
|
||||||
|
|
|
@ -1234,10 +1234,11 @@ IndexIterator* MMFilesSkiplistIndex::iteratorForCondition(
|
||||||
}
|
}
|
||||||
|
|
||||||
bool MMFilesSkiplistIndex::supportsFilterCondition(
|
bool MMFilesSkiplistIndex::supportsFilterCondition(
|
||||||
|
std::vector<std::shared_ptr<arangodb::Index>> const& allIndexes,
|
||||||
arangodb::aql::AstNode const* node,
|
arangodb::aql::AstNode const* node,
|
||||||
arangodb::aql::Variable const* reference, size_t itemsInIndex,
|
arangodb::aql::Variable const* reference, size_t itemsInIndex,
|
||||||
size_t& estimatedItems, double& estimatedCost) const {
|
size_t& estimatedItems, double& estimatedCost) const {
|
||||||
return SkiplistIndexAttributeMatcher::supportsFilterCondition(this, node, reference, itemsInIndex,
|
return SkiplistIndexAttributeMatcher::supportsFilterCondition(allIndexes, this, node, reference, itemsInIndex,
|
||||||
estimatedItems, estimatedCost);
|
estimatedItems, estimatedCost);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -299,7 +299,8 @@ class MMFilesSkiplistIndex final : public MMFilesPathBasedIndex {
|
||||||
|
|
||||||
void unload() override;
|
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&,
|
arangodb::aql::Variable const*, size_t, size_t&,
|
||||||
double&) const override;
|
double&) const override;
|
||||||
|
|
||||||
|
|
|
@ -545,12 +545,12 @@ RocksDBEdgeIndex::~RocksDBEdgeIndex() {}
|
||||||
|
|
||||||
/// @brief return a selectivity estimate for the index
|
/// @brief return a selectivity estimate for the index
|
||||||
double RocksDBEdgeIndex::selectivityEstimate(
|
double RocksDBEdgeIndex::selectivityEstimate(
|
||||||
arangodb::StringRef const* attribute) const {
|
arangodb::StringRef const& attribute) const {
|
||||||
TRI_ASSERT(!ServerState::instance()->isCoordinator());
|
TRI_ASSERT(!ServerState::instance()->isCoordinator());
|
||||||
if (_unique) {
|
if (_unique) {
|
||||||
return 1.0;
|
return 1.0;
|
||||||
}
|
}
|
||||||
if (attribute != nullptr && attribute->compare(_directionAttr)) {
|
if (!attribute.empty() && attribute.compare(_directionAttr)) {
|
||||||
return 0.0;
|
return 0.0;
|
||||||
}
|
}
|
||||||
TRI_ASSERT(_estimator != nullptr);
|
TRI_ASSERT(_estimator != nullptr);
|
||||||
|
@ -674,6 +674,7 @@ void RocksDBEdgeIndex::batchInsert(
|
||||||
|
|
||||||
/// @brief checks whether the index supports the condition
|
/// @brief checks whether the index supports the condition
|
||||||
bool RocksDBEdgeIndex::supportsFilterCondition(
|
bool RocksDBEdgeIndex::supportsFilterCondition(
|
||||||
|
std::vector<std::shared_ptr<arangodb::Index>> const& allIndexes,
|
||||||
arangodb::aql::AstNode const* node,
|
arangodb::aql::AstNode const* node,
|
||||||
arangodb::aql::Variable const* reference, size_t itemsInIndex,
|
arangodb::aql::Variable const* reference, size_t itemsInIndex,
|
||||||
size_t& estimatedItems, double& estimatedCost) const {
|
size_t& estimatedItems, double& estimatedCost) const {
|
||||||
|
|
|
@ -26,6 +26,7 @@
|
||||||
|
|
||||||
#include "Basics/Common.h"
|
#include "Basics/Common.h"
|
||||||
#include "Basics/LocalTaskQueue.h"
|
#include "Basics/LocalTaskQueue.h"
|
||||||
|
#include "Basics/StringRef.h"
|
||||||
#include "Indexes/Index.h"
|
#include "Indexes/Index.h"
|
||||||
#include "Indexes/IndexIterator.h"
|
#include "Indexes/IndexIterator.h"
|
||||||
#include "RocksDBEngine/RocksDBCuckooIndexEstimator.h"
|
#include "RocksDBEngine/RocksDBCuckooIndexEstimator.h"
|
||||||
|
@ -137,7 +138,7 @@ class RocksDBEdgeIndex final : public RocksDBIndex {
|
||||||
|
|
||||||
bool hasSelectivityEstimate() const override { return true; }
|
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;
|
RocksDBCuckooIndexEstimator<uint64_t>* estimator() override;
|
||||||
bool needToPersistEstimate() const override;
|
bool needToPersistEstimate() const override;
|
||||||
|
@ -152,7 +153,8 @@ class RocksDBEdgeIndex final : public RocksDBIndex {
|
||||||
|
|
||||||
bool hasBatchInsert() const override { return false; }
|
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&,
|
arangodb::aql::Variable const*, size_t, size_t&,
|
||||||
double&) const override;
|
double&) const override;
|
||||||
|
|
||||||
|
|
|
@ -354,6 +354,7 @@ Result RocksDBPrimaryIndex::removeInternal(transaction::Methods* trx,
|
||||||
|
|
||||||
/// @brief checks whether the index supports the condition
|
/// @brief checks whether the index supports the condition
|
||||||
bool RocksDBPrimaryIndex::supportsFilterCondition(
|
bool RocksDBPrimaryIndex::supportsFilterCondition(
|
||||||
|
std::vector<std::shared_ptr<arangodb::Index>> const& allIndexes,
|
||||||
arangodb::aql::AstNode const* node,
|
arangodb::aql::AstNode const* node,
|
||||||
arangodb::aql::Variable const* reference, size_t itemsInIndex,
|
arangodb::aql::Variable const* reference, size_t itemsInIndex,
|
||||||
size_t& estimatedItems, double& estimatedCost) const {
|
size_t& estimatedItems, double& estimatedCost) const {
|
||||||
|
|
|
@ -24,6 +24,7 @@
|
||||||
#ifndef ARANGOD_ROCKSDB_ENGINE_ROCKSDB_PRIMARY_INDEX_H
|
#ifndef ARANGOD_ROCKSDB_ENGINE_ROCKSDB_PRIMARY_INDEX_H
|
||||||
#define ARANGOD_ROCKSDB_ENGINE_ROCKSDB_PRIMARY_INDEX_H 1
|
#define ARANGOD_ROCKSDB_ENGINE_ROCKSDB_PRIMARY_INDEX_H 1
|
||||||
|
|
||||||
|
#include "Basics/StringRef.h"
|
||||||
#include "Indexes/Index.h"
|
#include "Indexes/Index.h"
|
||||||
#include "Indexes/IndexIterator.h"
|
#include "Indexes/IndexIterator.h"
|
||||||
#include "RocksDBEngine/RocksDBIndex.h"
|
#include "RocksDBEngine/RocksDBIndex.h"
|
||||||
|
@ -102,7 +103,7 @@ class RocksDBPrimaryIndex final : public RocksDBIndex {
|
||||||
|
|
||||||
bool hasSelectivityEstimate() const override { return true; }
|
bool hasSelectivityEstimate() const override { return true; }
|
||||||
|
|
||||||
double selectivityEstimate(StringRef const* = nullptr) const override {
|
double selectivityEstimate(StringRef const& = StringRef()) const override {
|
||||||
return 1.0;
|
return 1.0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -127,7 +128,8 @@ class RocksDBPrimaryIndex final : public RocksDBIndex {
|
||||||
LocalDocumentId& id,
|
LocalDocumentId& id,
|
||||||
TRI_voc_rid_t& revisionId) const;
|
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&,
|
arangodb::aql::Variable const*, size_t, size_t&,
|
||||||
double&) const override;
|
double&) const override;
|
||||||
|
|
||||||
|
|
|
@ -299,7 +299,7 @@ RocksDBVPackIndex::RocksDBVPackIndex(
|
||||||
RocksDBVPackIndex::~RocksDBVPackIndex() {}
|
RocksDBVPackIndex::~RocksDBVPackIndex() {}
|
||||||
|
|
||||||
double RocksDBVPackIndex::selectivityEstimate(
|
double RocksDBVPackIndex::selectivityEstimate(
|
||||||
arangodb::StringRef const*) const {
|
arangodb::StringRef const&) const {
|
||||||
TRI_ASSERT(!ServerState::instance()->isCoordinator());
|
TRI_ASSERT(!ServerState::instance()->isCoordinator());
|
||||||
if (_unique) {
|
if (_unique) {
|
||||||
return 1.0;
|
return 1.0;
|
||||||
|
@ -927,10 +927,12 @@ IndexIterator* RocksDBVPackIndex::lookup(transaction::Methods* trx,
|
||||||
}
|
}
|
||||||
|
|
||||||
bool RocksDBVPackIndex::supportsFilterCondition(
|
bool RocksDBVPackIndex::supportsFilterCondition(
|
||||||
|
std::vector<std::shared_ptr<arangodb::Index>> const& allIndexes,
|
||||||
arangodb::aql::AstNode const* node,
|
arangodb::aql::AstNode const* node,
|
||||||
arangodb::aql::Variable const* reference, size_t itemsInIndex,
|
arangodb::aql::Variable const* reference, size_t itemsInIndex,
|
||||||
size_t& estimatedItems, double& estimatedCost) const {
|
size_t& estimatedItems, double& estimatedCost) const {
|
||||||
return PersistentIndexAttributeMatcher::supportsFilterCondition(this, node, reference, itemsInIndex,
|
return PersistentIndexAttributeMatcher::supportsFilterCondition(
|
||||||
|
allIndexes, this, node, reference, itemsInIndex,
|
||||||
estimatedItems, estimatedCost);
|
estimatedItems, estimatedCost);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -28,6 +28,7 @@
|
||||||
|
|
||||||
#include "Aql/AstNode.h"
|
#include "Aql/AstNode.h"
|
||||||
#include "Basics/Common.h"
|
#include "Basics/Common.h"
|
||||||
|
#include "Basics/StringRef.h"
|
||||||
#include "Indexes/IndexIterator.h"
|
#include "Indexes/IndexIterator.h"
|
||||||
#include "RocksDBEngine/RocksDBCuckooIndexEstimator.h"
|
#include "RocksDBEngine/RocksDBCuckooIndexEstimator.h"
|
||||||
#include "RocksDBEngine/RocksDBIndex.h"
|
#include "RocksDBEngine/RocksDBIndex.h"
|
||||||
|
@ -152,7 +153,7 @@ class RocksDBVPackIndex : public RocksDBIndex {
|
||||||
|
|
||||||
bool hasSelectivityEstimate() const override { return true; }
|
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;
|
RocksDBCuckooIndexEstimator<uint64_t>* estimator() override;
|
||||||
bool needToPersistEstimate() const override;
|
bool needToPersistEstimate() const override;
|
||||||
|
@ -182,7 +183,8 @@ class RocksDBVPackIndex : public RocksDBIndex {
|
||||||
IndexIterator* lookup(transaction::Methods*,
|
IndexIterator* lookup(transaction::Methods*,
|
||||||
arangodb::velocypack::Slice const, bool reverse) const;
|
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&,
|
arangodb::aql::Variable const*, size_t, size_t&,
|
||||||
double&) const override;
|
double&) const override;
|
||||||
|
|
||||||
|
|
|
@ -573,7 +573,7 @@ std::pair<bool, bool> transaction::Methods::findIndexHandleForAndNode(
|
||||||
// check if the index supports the filter expression
|
// check if the index supports the filter expression
|
||||||
double estimatedCost;
|
double estimatedCost;
|
||||||
size_t estimatedItems;
|
size_t estimatedItems;
|
||||||
if (idx->supportsFilterCondition(node, reference, itemsInIndex,
|
if (idx->supportsFilterCondition(indexes, node, reference, itemsInIndex,
|
||||||
estimatedItems, estimatedCost)) {
|
estimatedItems, estimatedCost)) {
|
||||||
// index supports the filter condition
|
// index supports the filter condition
|
||||||
filterCost = estimatedCost;
|
filterCost = estimatedCost;
|
||||||
|
@ -661,7 +661,7 @@ bool transaction::Methods::findIndexHandleForAndNode(
|
||||||
// check if the index supports the filter expression
|
// check if the index supports the filter expression
|
||||||
double estimatedCost;
|
double estimatedCost;
|
||||||
size_t estimatedItems;
|
size_t estimatedItems;
|
||||||
bool supportsFilter = idx->supportsFilterCondition(node, reference, itemsInIndex,
|
bool supportsFilter = idx->supportsFilterCondition(indexes, node, reference, itemsInIndex,
|
||||||
estimatedItems, estimatedCost);
|
estimatedItems, estimatedCost);
|
||||||
|
|
||||||
// enable the following line to see index candidates considered with their
|
// 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.");
|
"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);
|
estimatedItems, estimatedCost);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -263,6 +263,7 @@ class EdgeIndexMock final : public arangodb::Index {
|
||||||
}
|
}
|
||||||
|
|
||||||
bool supportsFilterCondition(
|
bool supportsFilterCondition(
|
||||||
|
std::vector<std::shared_ptr<arangodb::Index>> const& /*allIndexes*/,
|
||||||
arangodb::aql::AstNode const* node,
|
arangodb::aql::AstNode const* node,
|
||||||
arangodb::aql::Variable const* reference,
|
arangodb::aql::Variable const* reference,
|
||||||
size_t itemsInIndex,
|
size_t itemsInIndex,
|
||||||
|
|
Loading…
Reference in New Issue