From 14064926b6b499d53ff9f6aa2fc8413d30b08c68 Mon Sep 17 00:00:00 2001 From: florijan Date: Mon, 11 Sep 2017 12:05:19 +0200 Subject: [PATCH] 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 --- src/query/plan/operator.cpp | 31 +++++++++++++++++-------------- src/query/plan/operator.hpp | 16 ++++++++-------- 2 files changed, 25 insertions(+), 22 deletions(-) diff --git a/src/query/plan/operator.cpp b/src/query/plan/operator.cpp index 6a2fdfbee..bb06fba50 100644 --- a/src/query/plan/operator.cpp +++ b/src/query/plan/operator.cpp @@ -1,6 +1,7 @@ #include #include #include +#include #include "query/plan/operator.hpp" @@ -312,10 +313,10 @@ std::unique_ptr ScanAllByLabelPropertyRange::MakeCursor( ExpressionEvaluator evaluator(frame, symbol_table, db, graph_view_); auto convert = [&evaluator](const auto &bound) -> std::experimental::optional> { - if (!bound) return std::experimental::nullopt; - return std::experimental::make_optional(utils::Bound( - bound.value().value()->Accept(evaluator), bound.value().type())); - }; + if (!bound) return std::experimental::nullopt; + return std::experimental::make_optional(utils::Bound( + bound.value().value()->Accept(evaluator), bound.value().type())); + }; return db.Vertices(label_, property_, convert(lower_bound()), convert(upper_bound()), graph_view_ == GraphView::NEW); }; @@ -2018,7 +2019,7 @@ OrderBy::OrderBy(const std::shared_ptr &input, ordering.emplace_back(ordering_expression_pair.first); order_by_.emplace_back(ordering_expression_pair.second); } - compare_ = TypedValueListCompare(ordering); + compare_ = TypedValueVectorCompare(ordering); } ACCEPT_WITH_INPUT(OrderBy) @@ -2041,17 +2042,19 @@ bool OrderBy::OrderByCursor::Pull(Frame &frame, ExpressionEvaluator evaluator(frame, symbol_table, db_); while (input_cursor_->Pull(frame, symbol_table)) { // collect the order_by elements - std::list order_by; + std::vector order_by; + order_by.reserve(self_.order_by_.size()); for (auto expression_ptr : self_.order_by_) { order_by.emplace_back(expression_ptr->Accept(evaluator)); } // collect the output elements - std::list output; + std::vector output; + output.reserve(self_.output_symbols_.size()); for (const Symbol &output_sym : self_.output_symbols_) 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(), @@ -2126,16 +2129,16 @@ bool OrderBy::TypedValueCompare(const TypedValue &a, const TypedValue &b) { } } -bool OrderBy::TypedValueListCompare::operator()( - const std::list &c1, const std::list &c2) const { - auto c1_it = c1.begin(); - auto c2_it = c2.begin(); +bool OrderBy::TypedValueVectorCompare::operator()( + const std::vector &c1, + const std::vector &c2) const { // ordering is invalid if there are more elements in the collections // then there are in the ordering_ vector - debug_assert(std::distance(c1_it, c1.end()) <= ordering_.size() && - std::distance(c2_it, c2.end()) <= ordering_.size(), + debug_assert(c1.size() <= ordering_.size() && c2.size() <= ordering_.size(), "Collections contain more elements then there are orderings"); + auto c1_it = c1.begin(); + auto c2_it = c2.begin(); auto ordering_it = ordering_.begin(); for (; c1_it != c1.end() && c2_it != c2.end(); c1_it++, c2_it++, ordering_it++) { diff --git a/src/query/plan/operator.hpp b/src/query/plan/operator.hpp index 7ee1f2fb3..40108b6f3 100644 --- a/src/query/plan/operator.hpp +++ b/src/query/plan/operator.hpp @@ -1351,24 +1351,24 @@ class OrderBy : public LogicalOperator { const auto &output_symbols() const { return output_symbols_; } 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 // defined TypedValueCompare, and also accepts a vector of Orderings // the define how respective elements compare - class TypedValueListCompare { + class TypedValueVectorCompare { public: - TypedValueListCompare() {} - TypedValueListCompare(const std::vector &ordering) + TypedValueVectorCompare() {} + TypedValueVectorCompare(const std::vector &ordering) : ordering_(ordering) {} - bool operator()(const std::list &c1, - const std::list &c2) const; + bool operator()(const std::vector &c1, + const std::vector &c2) const; private: std::vector ordering_; }; const std::shared_ptr input_; - TypedValueListCompare compare_; + TypedValueVectorCompare compare_; std::vector order_by_; const std::vector output_symbols_; @@ -1394,7 +1394,7 @@ class OrderBy : public LogicalOperator { // first pair element is the order-by list // second pair is the remember list // the cache is filled and sorted (only on first pair elem) on first Pull - std::vector, std::list>> cache_; + std::vector, std::vector>> cache_; // iterator over the cache_, maintains state between Pulls decltype(cache_.begin()) cache_it_ = cache_.begin(); };