Improve MERGE performance by using indices (#213)
This commit is contained in:
parent
0138d277d4
commit
5a8bda2531
@ -291,16 +291,17 @@ can serve as inputs to others and thus a sequence of operations is formed.")
|
|||||||
cpp<#)
|
cpp<#)
|
||||||
|
|
||||||
(lcp:define-class once (logical-operator)
|
(lcp:define-class once (logical-operator)
|
||||||
()
|
((symbols "std::vector<Symbol>" :scope :public))
|
||||||
(:documentation
|
(:documentation
|
||||||
"A logical operator whose Cursor returns true on the first Pull
|
"A logical operator whose Cursor returns true on the first Pull
|
||||||
and false on every following Pull.")
|
and false on every following Pull.")
|
||||||
(:public
|
(:public
|
||||||
#>cpp
|
#>cpp
|
||||||
|
Once(std::vector<Symbol> symbols = {}) : symbols_{std::move(symbols)} {}
|
||||||
DEFVISITABLE(HierarchicalLogicalOperatorVisitor);
|
DEFVISITABLE(HierarchicalLogicalOperatorVisitor);
|
||||||
UniqueCursorPtr MakeCursor(utils::MemoryResource *) const override;
|
UniqueCursorPtr MakeCursor(utils::MemoryResource *) const override;
|
||||||
std::vector<Symbol> ModifiedSymbols(const SymbolTable &) const override {
|
std::vector<Symbol> ModifiedSymbols(const SymbolTable &) const override {
|
||||||
return {};
|
return symbols_;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool HasSingleInput() const override;
|
bool HasSingleInput() const override;
|
||||||
|
@ -482,9 +482,16 @@ class RuleBasedPlanner {
|
|||||||
// version when generating the create part.
|
// version when generating the create part.
|
||||||
std::unordered_set<Symbol> bound_symbols_copy(context_->bound_symbols);
|
std::unordered_set<Symbol> bound_symbols_copy(context_->bound_symbols);
|
||||||
MatchContext match_ctx{matching, *context_->symbol_table, bound_symbols_copy, storage::View::NEW};
|
MatchContext match_ctx{matching, *context_->symbol_table, bound_symbols_copy, storage::View::NEW};
|
||||||
auto on_match = PlanMatching(match_ctx, nullptr);
|
|
||||||
|
std::vector<Symbol> bound_symbols(context_->bound_symbols.begin(), context_->bound_symbols.end());
|
||||||
|
|
||||||
|
auto once_with_symbols = std::make_unique<Once>(bound_symbols);
|
||||||
|
auto on_match = PlanMatching(match_ctx, std::move(once_with_symbols));
|
||||||
|
|
||||||
|
once_with_symbols = std::make_unique<Once>(std::move(bound_symbols));
|
||||||
// Use the original bound_symbols, so we fill it with new symbols.
|
// Use the original bound_symbols, so we fill it with new symbols.
|
||||||
auto on_create = GenCreateForPattern(*merge.pattern_, nullptr, *context_->symbol_table, context_->bound_symbols);
|
auto on_create = GenCreateForPattern(*merge.pattern_, std::move(once_with_symbols), *context_->symbol_table,
|
||||||
|
context_->bound_symbols);
|
||||||
for (auto &set : merge.on_create_) {
|
for (auto &set : merge.on_create_) {
|
||||||
on_create = HandleWriteClause(set, on_create, *context_->symbol_table, context_->bound_symbols);
|
on_create = HandleWriteClause(set, on_create, *context_->symbol_table, context_->bound_symbols);
|
||||||
MG_ASSERT(on_create, "Expected SET in MERGE ... ON CREATE");
|
MG_ASSERT(on_create, "Expected SET in MERGE ... ON CREATE");
|
||||||
|
@ -774,6 +774,26 @@ TYPED_TEST(TestPlanner, UnwindMergeNodeProperty) {
|
|||||||
DeleteListContent(&on_create);
|
DeleteListContent(&on_create);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TYPED_TEST(TestPlanner, UnwindMergeNodePropertyWithIndex) {
|
||||||
|
// Test UNWIND [1] AS i MERGE (n :label {prop: i}) with label-property index
|
||||||
|
AstStorage storage;
|
||||||
|
FakeDbAccessor dba;
|
||||||
|
const auto label_name = "label";
|
||||||
|
const auto label = dba.Label(label_name);
|
||||||
|
const auto property = PROPERTY_PAIR("prop");
|
||||||
|
dba.SetIndexCount(label, property.second, 1);
|
||||||
|
auto node_n = NODE("n", label_name);
|
||||||
|
node_n->properties_[storage.GetPropertyIx(property.first)] = IDENT("i");
|
||||||
|
auto *query = QUERY(SINGLE_QUERY(UNWIND(LIST(LITERAL(1)), AS("i")), MERGE(PATTERN(node_n))));
|
||||||
|
std::list<BaseOpChecker *> on_match{new ExpectScanAllByLabelPropertyValue(label, property, IDENT("i"))};
|
||||||
|
std::list<BaseOpChecker *> on_create{new ExpectCreateNode()};
|
||||||
|
auto symbol_table = query::MakeSymbolTable(query);
|
||||||
|
auto planner = MakePlanner<TypeParam>(&dba, storage, symbol_table, query);
|
||||||
|
CheckPlan(planner.plan(), symbol_table, ExpectUnwind(), ExpectMerge(on_match, on_create));
|
||||||
|
DeleteListContent(&on_match);
|
||||||
|
DeleteListContent(&on_create);
|
||||||
|
}
|
||||||
|
|
||||||
TYPED_TEST(TestPlanner, MultipleOptionalMatchReturn) {
|
TYPED_TEST(TestPlanner, MultipleOptionalMatchReturn) {
|
||||||
// Test OPTIONAL MATCH (n) OPTIONAL MATCH (m) RETURN n
|
// Test OPTIONAL MATCH (n) OPTIONAL MATCH (m) RETURN n
|
||||||
AstStorage storage;
|
AstStorage storage;
|
||||||
|
Loading…
Reference in New Issue
Block a user