mirror of https://gitee.com/bigwinds/arangodb
check filter condition and sort condition support for all index types
This commit is contained in:
parent
27bcd7ee84
commit
67de5480e8
|
@ -198,51 +198,53 @@ bool Condition::findIndexForAndNode (AstNode const* node,
|
||||||
// We can only iterate through a proper DNF
|
// We can only iterate through a proper DNF
|
||||||
TRI_ASSERT(node->type == NODE_TYPE_OPERATOR_NARY_AND);
|
TRI_ASSERT(node->type == NODE_TYPE_OPERATOR_NARY_AND);
|
||||||
|
|
||||||
|
static double const MaxFilterCost = 2.0;
|
||||||
|
static double const MaxSortCost = 2.0;
|
||||||
|
|
||||||
// This code is never responsible for the content of this pointer.
|
// This code is never responsible for the content of this pointer.
|
||||||
Index const* bestIndex = nullptr;
|
Index const* bestIndex = nullptr;
|
||||||
|
double bestCost = MaxFilterCost + MaxSortCost + std::numeric_limits<double>::epsilon();
|
||||||
|
|
||||||
static double const MaxFilterCost = 10.0;
|
|
||||||
static double const MaxSortCost = 10.0;
|
|
||||||
|
|
||||||
double bestCost = -1.0; // All costs are > 0, so if we have found one we can use it.
|
|
||||||
std::vector<Index const*> indexes = colNode->collection()->getIndexes();
|
std::vector<Index const*> indexes = colNode->collection()->getIndexes();
|
||||||
|
|
||||||
for (auto& idx : indexes) {
|
for (auto& idx : indexes) {
|
||||||
double filterCost = 0.0;
|
double filterCost = 0.0;
|
||||||
double sortCost = 0.0;
|
double sortCost = 0.0;
|
||||||
|
|
||||||
std::cout << "CHECKING INDEX : " << triagens::basics::JsonHelper::toString(idx->getInternals()->toJson(TRI_UNKNOWN_MEM_ZONE, false).json()) << "\n";
|
|
||||||
|
|
||||||
// check if the index supports the filter expression
|
// check if the index supports the filter expression
|
||||||
double estimatedCost;
|
double estimatedCost;
|
||||||
if (idx->supportsFilterCondition(node, reference, estimatedCost)) {
|
if (idx->supportsFilterCondition(node, reference, estimatedCost)) {
|
||||||
std::cout << "- INDEX SUPPORTS FILTER CONDITION\n";
|
// index supports the filter condition
|
||||||
// index supports the filter expression
|
|
||||||
filterCost = estimatedCost;
|
filterCost = estimatedCost;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
std::cout << "- INDEX DOES NOT SUPPORT FILTER CONDITION\n";
|
// index does not support the filter condition
|
||||||
filterCost = MaxFilterCost;
|
filterCost = MaxFilterCost;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (! sortCondition.isEmpty() &&
|
if (! sortCondition.isEmpty() &&
|
||||||
sortCondition.isOnlyAttributeAccess()) {
|
sortCondition.isOnlyAttributeAccess() &&
|
||||||
|
sortCondition.isUnidirectional()) {
|
||||||
|
// only go in here if we actually have a sort condition and it can in
|
||||||
|
// general be supported by an index. for this, a sort condition must not
|
||||||
|
// be empty, must consist only of attribute access, and all attributes
|
||||||
|
// must be sorted in the direction
|
||||||
double estimatedCost;
|
double estimatedCost;
|
||||||
if (idx->isSorted() &&
|
if (idx->isSorted() &&
|
||||||
idx->supportsSortCondition(&sortCondition, reference, estimatedCost)) {
|
idx->supportsSortCondition(&sortCondition, reference, estimatedCost)) {
|
||||||
std::cout << "- INDEX SUPPORTS SORT CONDITION\n";
|
// index supports the sort condition
|
||||||
sortCost = estimatedCost;
|
sortCost = estimatedCost;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
std::cout << "- INDEX DOES NOT SUPPORT SORT CONDITION\n";
|
// index does not support the sort condition
|
||||||
sortCost = MaxSortCost;
|
sortCost = MaxSortCost;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
std::cout << "- INDEX FILTER COST: " << filterCost << ", SORT COST: " << sortCost << "\n";
|
// std::cout << "INDEX: " << triagens::basics::JsonHelper::toString(idx->getInternals()->toJson(TRI_UNKNOWN_MEM_ZONE, false).json()) << ", FILTER COST: " << filterCost << ", SORT COST: " << sortCost << "\n";
|
||||||
double const totalCost = filterCost + sortCost;
|
double const totalCost = filterCost + sortCost;
|
||||||
|
|
||||||
if (bestCost < totalCost) {
|
if (totalCost < bestCost) {
|
||||||
bestIndex = idx;
|
bestIndex = idx;
|
||||||
bestCost = totalCost;
|
bestCost = totalCost;
|
||||||
}
|
}
|
||||||
|
@ -252,8 +254,6 @@ bool Condition::findIndexForAndNode (AstNode const* node,
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::cout << "We can use indexes for var: " << reference->name << " in collection " << colNode->collection()->getName() << ":" << std::endl;
|
|
||||||
std::cout << "We use: " << bestIndex->toJson() << std::endl;
|
|
||||||
usedIndexes.emplace_back(bestIndex);
|
usedIndexes.emplace_back(bestIndex);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
|
|
@ -65,15 +65,19 @@ SortCondition::SortCondition (std::vector<std::pair<AstNode const*, bool>> const
|
||||||
if (node->type == NODE_TYPE_REFERENCE) {
|
if (node->type == NODE_TYPE_REFERENCE) {
|
||||||
handled = true;
|
handled = true;
|
||||||
|
|
||||||
_fields.emplace_back(std::make_pair(static_cast<Variable const*>(node->getData())->name, fieldNames));
|
_fields.emplace_back(std::make_pair(static_cast<Variable const*>(node->getData()), fieldNames));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (! handled) {
|
if (! handled) {
|
||||||
_fields.emplace_back(std::pair<std::string, std::vector<triagens::basics::AttributeName>>());
|
_fields.emplace_back(std::pair<Variable const*, std::vector<triagens::basics::AttributeName>>());
|
||||||
_onlyAttributeAccess = false;
|
_onlyAttributeAccess = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (n == 0) {
|
||||||
|
_onlyAttributeAccess = false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
SortCondition::SortCondition (std::vector<std::pair<VariableId, bool>> const& sorts,
|
SortCondition::SortCondition (std::vector<std::pair<VariableId, bool>> const& sorts,
|
||||||
|
@ -83,6 +87,7 @@ SortCondition::SortCondition (std::vector<std::pair<VariableId, bool>> const& so
|
||||||
_onlyAttributeAccess(true) {
|
_onlyAttributeAccess(true) {
|
||||||
|
|
||||||
size_t const n = sorts.size();
|
size_t const n = sorts.size();
|
||||||
|
|
||||||
for (size_t i = 0; i < n; ++i) {
|
for (size_t i = 0; i < n; ++i) {
|
||||||
if (_unidirectional && i > 0 && sorts[i].second != sorts[i - 1].second) {
|
if (_unidirectional && i > 0 && sorts[i].second != sorts[i - 1].second) {
|
||||||
_unidirectional = false;
|
_unidirectional = false;
|
||||||
|
@ -103,19 +108,73 @@ SortCondition::SortCondition (std::vector<std::pair<VariableId, bool>> const& so
|
||||||
fieldNames.emplace_back(triagens::basics::AttributeName(node->getStringValue()));
|
fieldNames.emplace_back(triagens::basics::AttributeName(node->getStringValue()));
|
||||||
node = node->getMember(0);
|
node = node->getMember(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (node->type == NODE_TYPE_REFERENCE) {
|
if (node->type == NODE_TYPE_REFERENCE) {
|
||||||
handled = true;
|
handled = true;
|
||||||
|
|
||||||
_fields.emplace_back(std::make_pair(static_cast<Variable const*>(node->getData())->name, fieldNames));
|
_fields.emplace_back(std::make_pair(static_cast<Variable const*>(node->getData()), fieldNames));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (! handled) {
|
if (! handled) {
|
||||||
_fields.emplace_back(std::pair<std::string, std::vector<triagens::basics::AttributeName>>());
|
_fields.emplace_back(std::pair<Variable const*, std::vector<triagens::basics::AttributeName>>());
|
||||||
_onlyAttributeAccess = false;
|
_onlyAttributeAccess = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (n == 0) {
|
||||||
|
_onlyAttributeAccess = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// -----------------------------------------------------------------------------
|
||||||
|
// --SECTION-- public methods
|
||||||
|
// -----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
/// @brief returns the number of attributes in the sort condition covered
|
||||||
|
/// by the specified index fields
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
size_t SortCondition::isCoveredBy (Variable const* reference,
|
||||||
|
std::vector<std::vector<triagens::basics::AttributeName>> const& indexAttributes) const {
|
||||||
|
size_t coveredAttributes = 0;
|
||||||
|
|
||||||
|
for (size_t i = 0; i < indexAttributes.size(); ++i) {
|
||||||
|
if (i >= _fields.size()) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (reference != _fields[i].first) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto const& fieldNames = _fields[i].second;
|
||||||
|
if (fieldNames.size() != indexAttributes[i].size()) {
|
||||||
|
// different attribute path
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool found = true;
|
||||||
|
for (size_t j = 0; j < indexAttributes[i].size(); ++j) {
|
||||||
|
if (indexAttributes[i][j].shouldExpand ||
|
||||||
|
fieldNames[j] != indexAttributes[i][j].name) {
|
||||||
|
// expanded attribute or different attribute
|
||||||
|
found = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (! found) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// same attribute
|
||||||
|
++coveredAttributes;
|
||||||
|
}
|
||||||
|
|
||||||
|
return coveredAttributes;
|
||||||
}
|
}
|
||||||
|
|
||||||
// -----------------------------------------------------------------------------
|
// -----------------------------------------------------------------------------
|
||||||
|
|
|
@ -92,6 +92,22 @@ namespace triagens {
|
||||||
return _fields.empty();
|
return _fields.empty();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
/// @brief number of attributes in condition
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
inline size_t numAttributes () const {
|
||||||
|
return _fields.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
/// @brief returns the number of attributes in the sort condition covered
|
||||||
|
/// by the specified index fields
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
size_t isCoveredBy (Variable const*,
|
||||||
|
std::vector<std::vector<triagens::basics::AttributeName>> const&) const;
|
||||||
|
|
||||||
// -----------------------------------------------------------------------------
|
// -----------------------------------------------------------------------------
|
||||||
// --SECTION-- private variables
|
// --SECTION-- private variables
|
||||||
// -----------------------------------------------------------------------------
|
// -----------------------------------------------------------------------------
|
||||||
|
@ -108,7 +124,7 @@ namespace triagens {
|
||||||
/// @brief fields used in the sort conditions
|
/// @brief fields used in the sort conditions
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
std::vector<std::pair<std::string, std::vector<triagens::basics::AttributeName>>> _fields;
|
std::vector<std::pair<Variable const*, std::vector<triagens::basics::AttributeName>>> _fields;
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
/// @brief whether or not the sort is unidirectional
|
/// @brief whether or not the sort is unidirectional
|
||||||
|
|
|
@ -546,7 +546,10 @@ int EdgeIndex::sizeHint (size_t size) {
|
||||||
bool EdgeIndex::supportsFilterCondition (triagens::aql::AstNode const* node,
|
bool EdgeIndex::supportsFilterCondition (triagens::aql::AstNode const* node,
|
||||||
triagens::aql::Variable const* reference,
|
triagens::aql::Variable const* reference,
|
||||||
double& estimatedCost) const {
|
double& estimatedCost) const {
|
||||||
SimpleAttributeEqualityMatcher matcher({ { TRI_VOC_ATTRIBUTE_FROM }, { TRI_VOC_ATTRIBUTE_TO } });
|
SimpleAttributeEqualityMatcher matcher({
|
||||||
|
{ triagens::basics::AttributeName(TRI_VOC_ATTRIBUTE_FROM, false) },
|
||||||
|
{ triagens::basics::AttributeName(TRI_VOC_ATTRIBUTE_TO, false) }
|
||||||
|
});
|
||||||
return matcher.matchOne(this, node, reference, estimatedCost);
|
return matcher.matchOne(this, node, reference, estimatedCost);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -702,7 +702,7 @@ int HashIndex::removeMulti (TRI_doc_mptr_t const* doc, bool isRollback) {
|
||||||
bool HashIndex::supportsFilterCondition (triagens::aql::AstNode const* node,
|
bool HashIndex::supportsFilterCondition (triagens::aql::AstNode const* node,
|
||||||
triagens::aql::Variable const* reference,
|
triagens::aql::Variable const* reference,
|
||||||
double& estimatedCost) const {
|
double& estimatedCost) const {
|
||||||
SimpleAttributeEqualityMatcher matcher(fieldNames());
|
SimpleAttributeEqualityMatcher matcher(fields());
|
||||||
return matcher.matchAll(this, node, reference, estimatedCost);
|
return matcher.matchAll(this, node, reference, estimatedCost);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -437,6 +437,7 @@ bool Index::hasBatchInsert () const {
|
||||||
bool Index::supportsFilterCondition (triagens::aql::AstNode const* node,
|
bool Index::supportsFilterCondition (triagens::aql::AstNode const* node,
|
||||||
triagens::aql::Variable const* reference,
|
triagens::aql::Variable const* reference,
|
||||||
double& estimatedCost) const {
|
double& estimatedCost) const {
|
||||||
|
// by default, no filter conditions are supported
|
||||||
estimatedCost = 0.0;
|
estimatedCost = 0.0;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -448,6 +449,7 @@ bool Index::supportsFilterCondition (triagens::aql::AstNode const* node,
|
||||||
bool Index::supportsSortCondition (triagens::aql::SortCondition const* sortCondition,
|
bool Index::supportsSortCondition (triagens::aql::SortCondition const* sortCondition,
|
||||||
triagens::aql::Variable const* reference,
|
triagens::aql::Variable const* reference,
|
||||||
double& estimatedCost) const {
|
double& estimatedCost) const {
|
||||||
|
// by default, no sort conditions are supported
|
||||||
estimatedCost = 0.0;
|
estimatedCost = 0.0;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
|
@ -277,7 +277,10 @@ void PrimaryIndex::invokeOnAllElements (std::function<void(TRI_doc_mptr_t*)> wor
|
||||||
bool PrimaryIndex::supportsFilterCondition (triagens::aql::AstNode const* node,
|
bool PrimaryIndex::supportsFilterCondition (triagens::aql::AstNode const* node,
|
||||||
triagens::aql::Variable const* reference,
|
triagens::aql::Variable const* reference,
|
||||||
double& estimatedCost) const {
|
double& estimatedCost) const {
|
||||||
SimpleAttributeEqualityMatcher matcher({ { TRI_VOC_ATTRIBUTE_ID }, { TRI_VOC_ATTRIBUTE_KEY } });
|
SimpleAttributeEqualityMatcher matcher({
|
||||||
|
{ triagens::basics::AttributeName(TRI_VOC_ATTRIBUTE_ID, false) },
|
||||||
|
{ triagens::basics::AttributeName(TRI_VOC_ATTRIBUTE_KEY, false) }
|
||||||
|
});
|
||||||
return matcher.matchOne(this, node, reference, estimatedCost);
|
return matcher.matchOne(this, node, reference, estimatedCost);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -34,6 +34,7 @@
|
||||||
#include "Aql/Ast.h"
|
#include "Aql/Ast.h"
|
||||||
#include "Aql/AstNode.h"
|
#include "Aql/AstNode.h"
|
||||||
#include "Aql/Variable.h"
|
#include "Aql/Variable.h"
|
||||||
|
#include "Basics/AttributeNameParser.h"
|
||||||
#include "Indexes/Index.h"
|
#include "Indexes/Index.h"
|
||||||
#include "VocBase/vocbase.h"
|
#include "VocBase/vocbase.h"
|
||||||
|
|
||||||
|
@ -52,7 +53,7 @@ namespace triagens {
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
SimpleAttributeEqualityMatcher (std::vector<std::vector<std::string>> const& attributes)
|
SimpleAttributeEqualityMatcher (std::vector<std::vector<triagens::basics::AttributeName>> const& attributes)
|
||||||
: _attributes(attributes) {
|
: _attributes(attributes) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -217,7 +218,8 @@ namespace triagens {
|
||||||
|
|
||||||
bool match = true;
|
bool match = true;
|
||||||
for (size_t j = 0; j < _attributes[i].size(); ++j) {
|
for (size_t j = 0; j < _attributes[i].size(); ++j) {
|
||||||
if (_attributes[i][j] != fieldNames[j]) {
|
if (_attributes[i][j].shouldExpand ||
|
||||||
|
_attributes[i][j].name != fieldNames[j]) {
|
||||||
match = false;
|
match = false;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -243,7 +245,7 @@ namespace triagens {
|
||||||
/// @brief array of attributes used for comparisons
|
/// @brief array of attributes used for comparisons
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
std::vector<std::vector<std::string>> _attributes;
|
std::vector<std::vector<triagens::basics::AttributeName>> _attributes;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -1032,14 +1032,27 @@ bool SkiplistIndex::supportsFilterCondition (triagens::aql::AstNode const* node,
|
||||||
return estimatedCost * static_cast<double>(values);
|
return estimatedCost * static_cast<double>(values);
|
||||||
}
|
}
|
||||||
|
|
||||||
estimatedCost = 1.0; // set to highest possible cost by default
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool SkiplistIndex::supportsSortCondition (triagens::aql::SortCondition const* sortCondition,
|
bool SkiplistIndex::supportsSortCondition (triagens::aql::SortCondition const* sortCondition,
|
||||||
triagens::aql::Variable const* reference,
|
triagens::aql::Variable const* reference,
|
||||||
double& estimatedCost) const {
|
double& estimatedCost) const {
|
||||||
|
TRI_ASSERT(sortCondition != nullptr);
|
||||||
|
|
||||||
|
if (! _useExpansion &&
|
||||||
|
sortCondition->isUnidirectional() &&
|
||||||
|
sortCondition->isOnlyAttributeAccess()) {
|
||||||
|
|
||||||
|
size_t const coveredAttributes = sortCondition->isCoveredBy(reference, _fields);
|
||||||
|
|
||||||
|
if (coveredAttributes >= sortCondition->numAttributes()) {
|
||||||
estimatedCost = 0.0;
|
estimatedCost = 0.0;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
estimatedCost = 1.0;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -238,7 +238,7 @@ namespace triagens {
|
||||||
}
|
}
|
||||||
|
|
||||||
bool isSorted () const override final {
|
bool isSorted () const override final {
|
||||||
return false;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool hasSelectivityEstimate () const override final {
|
bool hasSelectivityEstimate () const override final {
|
||||||
|
|
Loading…
Reference in New Issue