Skip to content

Commit fd0f631

Browse files
Cypher 5 2025.08 release (#1378)
1 parent 6a9690f commit fd0f631

File tree

6 files changed

+215
-38
lines changed

6 files changed

+215
-38
lines changed

antora.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,4 +6,4 @@ nav:
66
- modules/ROOT/content-nav.adoc
77
asciidoc:
88
attributes:
9-
neo4j-version: '2025.07'
9+
neo4j-version: '2025.08'

modules/ROOT/pages/clauses/match.adoc

Lines changed: 19 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -639,10 +639,26 @@ RETURN relationshipType, count(r) AS relationshipCount
639639
[[dynamic-match-caveats]]
640640
=== Performance caveats
641641

642-
`MATCH` queries using dynamic values may not be as performant as those using static values.
643-
This is because the xref:planning-and-tuning/execution-plans.adoc[Cypher planner] uses statically available information when planning queries to determine whether to use an xref:indexes/search-performance-indexes/index.adoc[index] or not, and this is not possible when using dynamic values.
642+
`MATCH` queries that use dynamic values may not perform as well as those with static values.
643+
Neo4j is actively working to improve the performance of these queries.
644+
The table below outlines performance caveats for specific Neo4j versions.
644645

645-
As a result, `MATCH` queries using dynamic values cannot leverage xref:planning-and-tuning/operators/operators-detail.adoc#leaf-operators[index scans or seeks] and must instead use the xref:planning-and-tuning/operators/operators-detail.adoc#query-plan-all-nodes-scan[`AllNodesScan`] operator, which reads all nodes from the node store and is therefore more costly.
646+
.Neo4j versions and performance caveats
647+
[%header,cols="a,5a"]
648+
|===
649+
| Neo4j versions | Performance caveat
650+
651+
| 5.26 -- 2025.07
652+
| The xref:planning-and-tuning/execution-plans.adoc[Cypher planner] is not able to leverage xref:indexes/search-performance-indexes/index.adoc[indexes] with xref:planning-and-tuning/operators/operators-detail.adoc#leaf-operators[index scans or seeks] and must instead utilize the xref:planning-and-tuning/operators/operators-detail.adoc#query-plan-all-nodes-scan[`AllNodesScan`] operator, which reads all nodes from the node store and is therefore more costly.
653+
654+
| 2025.08 -- current
655+
| The Cypher planner is able to leverage xref:indexes/search-performance-indexes/using-indexes.adoc#token-lookup-indexes[token lookup indexes] when matching node labels and relationship types dynamically.
656+
This is enabled by the introduction of three new query plan operators:
657+
xref:planning-and-tuning/operators/operators-detail.adoc#query-plan-dynamic-label-node-lookup[`DynamicLabelNodeLookup`], xref:planning-and-tuning/operators/operators-detail.adoc#query-plan-dynamic-directed-relationship-type-lookup[`DynamicDirectedRelationshipTypeLookup`], and xref:planning-and-tuning/operators/operators-detail.adoc#query-plan-dynamic-undirected-relationship-type-lookup[`DynamicUndirectedRelationshipTypeLookup`].
658+
It is not, however, able to use indexes on property values.
659+
For example, `MATCH (n:$(Label) {foo: bar})` will not use any indexes on `n.foo` but can use a `DynamicLabelNodeLookup` on `$(label)`.
660+
661+
|===
646662

647663
[[further-reading]]
648664
=== Further reading

modules/ROOT/pages/clauses/merge.adoc

Lines changed: 15 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -741,42 +741,23 @@ RETURN greta.name AS name, labels(greta) AS labels, type(rel) AS relType, collec
741741
[[dynamic-merge-caveats]]
742742
=== Performance caveats
743743

744-
`MERGE` queries that use dynamic values may not be as performant as those using static values.
745-
This is because the xref:planning-and-tuning/execution-plans.adoc[Cypher planner] uses statically available information when planning queries to determine whether to use an xref:indexes/search-performance-indexes/index.adoc[index] or not, and this is not possible when using dynamic values.
744+
`MERGE` queries that use dynamic values may not perform as well as those with static values.
745+
Neo4j is actively working to improve the performance of these queries.
746+
The table below outlines performance caveats for specific Neo4j versions.
746747

747-
As a result, `MERGE` queries with dynamic values cannot leverage xref:planning-and-tuning/operators/operators-detail.adoc#leaf-operators[index scans or seeks] and must instead use the xref:planning-and-tuning/operators/operators-detail.adoc#query-plan-all-nodes-scan[`AllNodesScan`] operator, which reads all nodes from the node store and is therefore more costly.
748-
749-
To circumvent possible performance issues, place the dynamic labels or relationship types within `ON CREATE` or `ON MATCH` subclauses.
750-
751-
.Parameters
752-
[source, parameters]
753-
----
754-
{
755-
"onMatchLabels": ["Filmmaker", "AwardRecipient"],
756-
"onCreateLabels": ["ScreenWriter", "AwardWinner"]
757-
}
758-
----
759-
760-
.Merge nodes using dynamic values in `ON CREATE` and `ON MATCH` subclauses
761-
[source, cypher]
762-
----
763-
MERGE (n:Person {name: "Greta Gerwig"})
764-
ON MATCH
765-
SET n:$($onMatchLabels)
766-
ON CREATE
767-
SET n:$($onCreateLabels)
768-
RETURN labels(n) AS gretaLabels
769-
----
770-
771-
Because a `Person` node with the `name` "Greta Gerwig" already exists, this query will only `SET` the dynamic labels added to the `ON MATCH` subclause.
772-
773-
.Result
774-
[role="queryresult",options="footer",cols="1*<m"]
748+
.Neo4j versions and performance caveats
749+
[%header,cols="a,5a"]
775750
|===
776-
| gretaLabels
751+
| Neo4j versions | Performance caveat
777752

778-
| ["Person", "Director", "Filmmaker", "AwardRecipient"]
753+
| 5.26 -- 2025.07
754+
| The xref:planning-and-tuning/execution-plans.adoc[Cypher planner] is not able to leverage xref:indexes/search-performance-indexes/index.adoc[indexes] with xref:planning-and-tuning/operators/operators-detail.adoc#leaf-operators[index scans or seeks] and must instead utilize the xref:planning-and-tuning/operators/operators-detail.adoc#query-plan-all-nodes-scan[`AllNodesScan`] operator, which reads all nodes from the node store and is therefore more costly.
779755

780-
1+d|Rows: 1
781-
|===
756+
| 2025.08 -- current
757+
| The Cypher planner is able to leverage xref:indexes/search-performance-indexes/using-indexes.adoc#token-lookup-indexes[token lookup indexes] when matching node labels and relationship types dynamically.
758+
This is enabled by the introduction of three new query plan operators:
759+
xref:planning-and-tuning/operators/operators-detail.adoc#query-plan-dynamic-label-node-lookup[`DynamicLabelNodeLookup`], xref:planning-and-tuning/operators/operators-detail.adoc#query-plan-dynamic-directed-relationship-type-lookup[`DynamicDirectedRelationshipTypeLookup`], and xref:planning-and-tuning/operators/operators-detail.adoc#query-plan-dynamic-undirected-relationship-type-lookup[`DynamicUndirectedRelationshipTypeLookup`].
760+
It is not, however, able to use indexes on property values.
761+
For example, `MERGE (n:$(Label) {foo: bar})` will not use any indexes on `n.foo` but can use a `DynamicLabelNodeLookup` on `$(label)`.
782762

763+
|===

modules/ROOT/pages/deprecations-additions-removals-compatibility.adoc

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,31 @@ For more information, see:
2828
* link:https://neo4j.com/docs/cypher-manual/25/introduction/[Cypher 25 Manual]
2929
====
3030

31+
[[cypher-deprecations-additions-removals-2025.08]]
32+
== Neo4j 2025.08
33+
34+
=== Updated in Cypher 5
35+
36+
[cols="2", options="header"]
37+
|===
38+
| Feature
39+
| Details
40+
41+
a|
42+
label:functionality[]
43+
label:updated[]
44+
[source, cypher]
45+
----
46+
PROFILE
47+
WITH "Person" AS label
48+
MATCH (people:$(label))
49+
RETURN people.name
50+
----
51+
52+
| Cypher can now leverage xref:indexes/search-performance-indexes/using-indexes.adoc#token-lookup-indexes[token lookup indexes] when planning queries with xref:clauses/match.adoc#dynamic-match[dynamic labels and relationship types].
53+
This is enabled by the introduction of three new query plan operators: xref:planning-and-tuning/operators/operators-detail.adoc#query-plan-dynamic-label-node-lookup[`DynamicLabelNodeLookup`], xref:planning-and-tuning/operators/operators-detail.adoc#query-plan-dynamic-directed-relationship-type-lookup[`DynamicDirectedRelationshipTypeLookup`], and xref:planning-and-tuning/operators/operators-detail.adoc#query-plan-dynamic-undirected-relationship-type-lookup[`DynamicUndirectedRelationshipTypeLookup`].
54+
|===
55+
3156
[[cypher-deprecations-additions-removals-2025.06]]
3257
== Neo4j 2025.06
3358

modules/ROOT/pages/planning-and-tuning/operators/index.adoc

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -212,6 +212,25 @@ Restricts the xref:planning-and-tuning/runtimes/index.adoc[Cypher runtime] to no
212212
| label:yes[]
213213
|
214214

215+
| xref:planning-and-tuning/operators/operators-detail.adoc#query-plan-dynamic-label-node-lookup[DynamicLabelNodeLookup]
216+
| Allows Cypher to use token lookup indexes when planning queries using dynamic node labels.
217+
| label:yes[]
218+
|
219+
| label:new[Introduced in Neo4j 2025.08]
220+
221+
222+
| xref:planning-and-tuning/operators/operators-detail.adoc#query-plan-dynamic-directed-relationship-type-lookup[DynamicDirectedRelationshipTypeLookup]
223+
| Allows Cypher to use token lookup indexes when planning queries using dynamic relationship types in directed relationship patterns.
224+
| label:yes[]
225+
|
226+
| label:new[Introduced in Neo4j 2025.08]
227+
228+
| xref:planning-and-tuning/operators/operators-detail.adoc#query-plan-dynamic-undirected-relationship-type-lookup[DynamicUndirectedRelationshipTypeLookup]
229+
| Allows Cypher to use token lookup indexes when planning queries using dynamic relationship types in undirected relationship patterns.
230+
| label:yes[]
231+
|
232+
| label:new[Introduced in Neo4j 2025.08]
233+
215234
| xref::planning-and-tuning/operators/operators-detail.adoc#query-plan-eager[Eager]
216235
| For isolation purposes, `Eager` ensures that operations affecting subsequent operations are executed fully for the whole dataset before continuing execution.
217236
|

modules/ROOT/pages/planning-and-tuning/operators/operators-detail.adoc

Lines changed: 136 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2599,6 +2599,142 @@ Total database accesses: 106
25992599
26002600
======
26012601

2602+
[role=label--new-2025.08]
2603+
[[query-plan-dynamic-label-node-lookup]]
2604+
=== Dynamic Label Node Lookup
2605+
2606+
Allows Cypher to use xref:indexes/search-performance-indexes/using-indexes.adoc#token-lookup-indexes[token lookup indexes] when planning queries using xref:clauses/match.adoc#dynamic-match[dynamic node labels].
2607+
2608+
.DynamicLabelNodeLookup
2609+
======
2610+
2611+
.Query
2612+
[source, cypher]
2613+
----
2614+
PROFILE
2615+
WITH "Person" AS label
2616+
MATCH (people:$(label))
2617+
RETURN people.name
2618+
----
2619+
2620+
.Query Plan
2621+
[role="queryplan", subs="attributes+"]
2622+
----
2623+
Planner COST
2624+
2625+
Runtime PIPELINED
2626+
2627+
Runtime version {neo4j-version}
2628+
2629+
Batch size 128
2630+
2631+
2632+
+---------------------------+----+------------------------------+----------------+------+---------+----------------+------------------------+-----------+---------------------+
2633+
| Operator | Id | Details | Estimated Rows | Rows | DB Hits | Memory (Bytes) | Page Cache Hits/Misses | Time (ms) | Pipeline |
2634+
+---------------------------+----+------------------------------+----------------+------+---------+----------------+------------------------+-----------+---------------------+
2635+
| +ProduceResults | 0 | `people.name` | 26 | 14 | 0 | 0 | | | |
2636+
| | +----+------------------------------+----------------+------+---------+----------------+ | | |
2637+
| +Projection | 1 | people.name AS `people.name` | 26 | 14 | 28 | | | | |
2638+
| | +----+------------------------------+----------------+------+---------+----------------+ | | |
2639+
| +Apply | 2 | | 26 | 14 | 0 | | | | |
2640+
| |\ +----+------------------------------+----------------+------+---------+----------------+ | | |
2641+
| | +DynamicLabelNodeLookup | 3 | people:$all(label) | 26 | 14 | 15 | 1832 | 2/0 | 0.366 | Fused in Pipeline 1 |
2642+
| | +----+------------------------------+----------------+------+---------+----------------+------------------------+-----------+---------------------+
2643+
| +Projection | 4 | $autostring_0 AS label | 1 | 1 | 0 | | | | Fused in Pipeline 0 |
2644+
+---------------------------+----+------------------------------+----------------+------+---------+----------------+------------------------+-----------+---------------------+
2645+
----
2646+
======
2647+
2648+
[role=label--new-2025.08]
2649+
[[query-plan-dynamic-directed-relationship-type-lookup]]
2650+
=== Dynamic Directed Relationship Type Lookup
2651+
2652+
Allows Cypher to use xref:indexes/search-performance-indexes/using-indexes.adoc#token-lookup-indexes[token lookup indexes] when planning queries using xref:clauses/match.adoc#dynamic-match[dynamic relationship types] in directed relationship patterns.
2653+
2654+
.DynamicDirectedRelationshipTypeLookup
2655+
======
2656+
2657+
.Query
2658+
[source, cypher]
2659+
----
2660+
PROFILE
2661+
WITH "FRIENDS_WITH" AS relType
2662+
MATCH ()-[r:$(relType)]->()
2663+
RETURN count(r) as relCount
2664+
----
2665+
2666+
.Query Plan
2667+
[role="queryplan", subs="attributes+"]
2668+
----
2669+
Planner COST
2670+
2671+
Runtime PIPELINED
2672+
2673+
Runtime version {neo4j-version}
2674+
2675+
Batch size 128
2676+
2677+
+------------------------------------------+----+--------------------------+----------------+------+---------+----------------+------------------------+-----------+---------------------+
2678+
| Operator | Id | Details | Estimated Rows | Rows | DB Hits | Memory (Bytes) | Page Cache Hits/Misses | Time (ms) | Pipeline |
2679+
+------------------------------------------+----+--------------------------+----------------+------+---------+----------------+------------------------+-----------+---------------------+
2680+
| +ProduceResults | 0 | relCount | 1 | 1 | 0 | 0 | 0/0 | 0.022 | In Pipeline 2 |
2681+
| | +----+--------------------------+----------------+------+---------+----------------+------------------------+-----------+---------------------+
2682+
| +EagerAggregation | 1 | count(r) AS relCount | 1 | 1 | 0 | 40 | | | |
2683+
| | +----+--------------------------+----------------+------+---------+----------------+ | | |
2684+
| +Apply | 2 | | 21 | 12 | 0 | | | | |
2685+
| |\ +----+--------------------------+----------------+------+---------+----------------+ | | |
2686+
| | +DynamicDirectedRelationshipTypeLookup | 3 | ()-[r:$all(relType)]->() | 21 | 12 | 13 | 1968 | 2/0 | 0.359 | Fused in Pipeline 1 |
2687+
| | +----+--------------------------+----------------+------+---------+----------------+------------------------+-----------+---------------------+
2688+
| +Projection | 4 | $autostring_0 AS relType | 1 | 1 | 0 | | | | Fused in Pipeline 0 |
2689+
+------------------------------------------+----+--------------------------+----------------+------+---------+----------------+------------------------+-----------+---------------------+
2690+
----
2691+
======
2692+
2693+
2694+
[role=label--new-2025.08]
2695+
[[query-plan-dynamic-undirected-relationship-type-lookup]]
2696+
=== Dynamic Undirected Relationship Type Lookup
2697+
2698+
Allows Cypher to use xref:indexes/search-performance-indexes/using-indexes.adoc#token-lookup-indexes[token lookup indexes] when planning queries using dynamic relationship types in undirected relationship patterns.
2699+
2700+
.DynamicUndirectedRelationshipTypeLookup
2701+
======
2702+
2703+
.Query
2704+
[source, cypher]
2705+
----
2706+
PROFILE
2707+
WITH "FRIENDS_WITH" AS relType
2708+
MATCH ()-[r:$(relType)]-()
2709+
RETURN count(r) as relCount
2710+
----
2711+
2712+
.Query Plan
2713+
[role="queryplan", subs="attributes+"]
2714+
----
2715+
Planner COST
2716+
2717+
Runtime PIPELINED
2718+
2719+
Runtime version {neo4j-version}
2720+
2721+
Batch size 128
2722+
2723+
+--------------------------------------------+----+--------------------------+----------------+------+---------+----------------+------------------------+-----------+---------------------+
2724+
| Operator | Id | Details | Estimated Rows | Rows | DB Hits | Memory (Bytes) | Page Cache Hits/Misses | Time (ms) | Pipeline |
2725+
+--------------------------------------------+----+--------------------------+----------------+------+---------+----------------+------------------------+-----------+---------------------+
2726+
| +ProduceResults | 0 | relCount | 1 | 1 | 0 | 0 | 0/0 | 0.011 | In Pipeline 2 |
2727+
| | +----+--------------------------+----------------+------+---------+----------------+------------------------+-----------+---------------------+
2728+
| +EagerAggregation | 1 | count(r) AS relCount | 1 | 1 | 0 | 40 | | | |
2729+
| | +----+--------------------------+----------------+------+---------+----------------+ | | |
2730+
| +Apply | 2 | | 42 | 24 | 0 | | | | |
2731+
| |\ +----+--------------------------+----------------+------+---------+----------------+ | | |
2732+
| | +DynamicUndirectedRelationshipTypeLookup | 3 | ()-[r:$all(relType)]-() | 42 | 24 | 13 | 1968 | 2/0 | 0.121 | Fused in Pipeline 1 |
2733+
| | +----+--------------------------+----------------+------+---------+----------------+------------------------+-----------+---------------------+
2734+
| +Projection | 4 | $autostring_0 AS relType | 1 | 1 | 0 | | | | Fused in Pipeline 0 |
2735+
+--------------------------------------------+----+--------------------------+----------------+------+---------+----------------+------------------------+-----------+---------------------+
2736+
----
2737+
======
26022738

26032739
[[nested-loops-join-operators]]
26042740
== Nested loops and join operators

0 commit comments

Comments
 (0)