plan::OrderBy - use vector instead of list
Summary: Reduces latency on LDBC query 9 from 7.9sec to 6.8sec (14%). That query has 650k rows in ORDER BY, 3 ordering elements and 10ish values get returned (both of them are now accumulated into vectors). Reviewers: buda, mislav.bradac Reviewed By: mislav.bradac Subscribers: pullbot Differential Revision: https://phabricator.memgraph.io/D775
This commit is contained in:
parent
35f726dfd2
commit
14064926b6
@ -1,6 +1,7 @@
|
|||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <limits>
|
#include <limits>
|
||||||
#include <type_traits>
|
#include <type_traits>
|
||||||
|
#include <utility>
|
||||||
|
|
||||||
#include "query/plan/operator.hpp"
|
#include "query/plan/operator.hpp"
|
||||||
|
|
||||||
@ -2018,7 +2019,7 @@ OrderBy::OrderBy(const std::shared_ptr<LogicalOperator> &input,
|
|||||||
ordering.emplace_back(ordering_expression_pair.first);
|
ordering.emplace_back(ordering_expression_pair.first);
|
||||||
order_by_.emplace_back(ordering_expression_pair.second);
|
order_by_.emplace_back(ordering_expression_pair.second);
|
||||||
}
|
}
|
||||||
compare_ = TypedValueListCompare(ordering);
|
compare_ = TypedValueVectorCompare(ordering);
|
||||||
}
|
}
|
||||||
|
|
||||||
ACCEPT_WITH_INPUT(OrderBy)
|
ACCEPT_WITH_INPUT(OrderBy)
|
||||||
@ -2041,17 +2042,19 @@ bool OrderBy::OrderByCursor::Pull(Frame &frame,
|
|||||||
ExpressionEvaluator evaluator(frame, symbol_table, db_);
|
ExpressionEvaluator evaluator(frame, symbol_table, db_);
|
||||||
while (input_cursor_->Pull(frame, symbol_table)) {
|
while (input_cursor_->Pull(frame, symbol_table)) {
|
||||||
// collect the order_by elements
|
// collect the order_by elements
|
||||||
std::list<TypedValue> order_by;
|
std::vector<TypedValue> order_by;
|
||||||
|
order_by.reserve(self_.order_by_.size());
|
||||||
for (auto expression_ptr : self_.order_by_) {
|
for (auto expression_ptr : self_.order_by_) {
|
||||||
order_by.emplace_back(expression_ptr->Accept(evaluator));
|
order_by.emplace_back(expression_ptr->Accept(evaluator));
|
||||||
}
|
}
|
||||||
|
|
||||||
// collect the output elements
|
// collect the output elements
|
||||||
std::list<TypedValue> output;
|
std::vector<TypedValue> output;
|
||||||
|
output.reserve(self_.output_symbols_.size());
|
||||||
for (const Symbol &output_sym : self_.output_symbols_)
|
for (const Symbol &output_sym : self_.output_symbols_)
|
||||||
output.emplace_back(frame[output_sym]);
|
output.emplace_back(frame[output_sym]);
|
||||||
|
|
||||||
cache_.emplace_back(order_by, output);
|
cache_.emplace_back(std::move(order_by), std::move(output));
|
||||||
}
|
}
|
||||||
|
|
||||||
std::sort(cache_.begin(), cache_.end(),
|
std::sort(cache_.begin(), cache_.end(),
|
||||||
@ -2126,16 +2129,16 @@ bool OrderBy::TypedValueCompare(const TypedValue &a, const TypedValue &b) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool OrderBy::TypedValueListCompare::operator()(
|
bool OrderBy::TypedValueVectorCompare::operator()(
|
||||||
const std::list<TypedValue> &c1, const std::list<TypedValue> &c2) const {
|
const std::vector<TypedValue> &c1,
|
||||||
auto c1_it = c1.begin();
|
const std::vector<TypedValue> &c2) const {
|
||||||
auto c2_it = c2.begin();
|
|
||||||
// ordering is invalid if there are more elements in the collections
|
// ordering is invalid if there are more elements in the collections
|
||||||
// then there are in the ordering_ vector
|
// then there are in the ordering_ vector
|
||||||
debug_assert(std::distance(c1_it, c1.end()) <= ordering_.size() &&
|
debug_assert(c1.size() <= ordering_.size() && c2.size() <= ordering_.size(),
|
||||||
std::distance(c2_it, c2.end()) <= ordering_.size(),
|
|
||||||
"Collections contain more elements then there are orderings");
|
"Collections contain more elements then there are orderings");
|
||||||
|
|
||||||
|
auto c1_it = c1.begin();
|
||||||
|
auto c2_it = c2.begin();
|
||||||
auto ordering_it = ordering_.begin();
|
auto ordering_it = ordering_.begin();
|
||||||
for (; c1_it != c1.end() && c2_it != c2.end();
|
for (; c1_it != c1.end() && c2_it != c2.end();
|
||||||
c1_it++, c2_it++, ordering_it++) {
|
c1_it++, c2_it++, ordering_it++) {
|
||||||
|
@ -1351,24 +1351,24 @@ class OrderBy : public LogicalOperator {
|
|||||||
const auto &output_symbols() const { return output_symbols_; }
|
const auto &output_symbols() const { return output_symbols_; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// custom Comparator type for comparing lists of TypedValues
|
// custom Comparator type for comparing vectors of TypedValues
|
||||||
// does lexicographical ordering of elements based on the above
|
// does lexicographical ordering of elements based on the above
|
||||||
// defined TypedValueCompare, and also accepts a vector of Orderings
|
// defined TypedValueCompare, and also accepts a vector of Orderings
|
||||||
// the define how respective elements compare
|
// the define how respective elements compare
|
||||||
class TypedValueListCompare {
|
class TypedValueVectorCompare {
|
||||||
public:
|
public:
|
||||||
TypedValueListCompare() {}
|
TypedValueVectorCompare() {}
|
||||||
TypedValueListCompare(const std::vector<Ordering> &ordering)
|
TypedValueVectorCompare(const std::vector<Ordering> &ordering)
|
||||||
: ordering_(ordering) {}
|
: ordering_(ordering) {}
|
||||||
bool operator()(const std::list<TypedValue> &c1,
|
bool operator()(const std::vector<TypedValue> &c1,
|
||||||
const std::list<TypedValue> &c2) const;
|
const std::vector<TypedValue> &c2) const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::vector<Ordering> ordering_;
|
std::vector<Ordering> ordering_;
|
||||||
};
|
};
|
||||||
|
|
||||||
const std::shared_ptr<LogicalOperator> input_;
|
const std::shared_ptr<LogicalOperator> input_;
|
||||||
TypedValueListCompare compare_;
|
TypedValueVectorCompare compare_;
|
||||||
std::vector<Expression *> order_by_;
|
std::vector<Expression *> order_by_;
|
||||||
const std::vector<Symbol> output_symbols_;
|
const std::vector<Symbol> output_symbols_;
|
||||||
|
|
||||||
@ -1394,7 +1394,7 @@ class OrderBy : public LogicalOperator {
|
|||||||
// first pair element is the order-by list
|
// first pair element is the order-by list
|
||||||
// second pair is the remember list
|
// second pair is the remember list
|
||||||
// the cache is filled and sorted (only on first pair elem) on first Pull
|
// the cache is filled and sorted (only on first pair elem) on first Pull
|
||||||
std::vector<std::pair<std::list<TypedValue>, std::list<TypedValue>>> cache_;
|
std::vector<std::pair<std::vector<TypedValue>, std::vector<TypedValue>>> cache_;
|
||||||
// iterator over the cache_, maintains state between Pulls
|
// iterator over the cache_, maintains state between Pulls
|
||||||
decltype(cache_.begin()) cache_it_ = cache_.begin();
|
decltype(cache_.begin()) cache_it_ = cache_.begin();
|
||||||
};
|
};
|
||||||
|
Loading…
Reference in New Issue
Block a user