diff --git a/modules/ROOT/pages/clauses/match.adoc b/modules/ROOT/pages/clauses/match.adoc index 6304b38e3..e3b162018 100644 --- a/modules/ROOT/pages/clauses/match.adoc +++ b/modules/ROOT/pages/clauses/match.adoc @@ -649,15 +649,33 @@ The table below outlines performance caveats for specific Neo4j versions. | Neo4j versions | Performance caveat | 5.26 -- 2025.07 -| 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. +| 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. -| 2025.08 -- current +| 2025.08 -- 2025.10 | 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. 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`]. It is not, however, able to use indexes on property values. For example, `MATCH (n:$(Label) {foo: bar})` will not use any indexes on `n.foo` but can use a `DynamicLabelNodeLookup` on `$(label)`. +| 2025.11 -- current +a| The Cypher planner is able to leverage indexes on property values, however: + +* It only supports exact seeks on range indexes (no full text or spatial). +* The index order cannot be leveraged, so the planner must insert separate ordering if required later on in the query. +* Parallel runtime seeks and scans are single-threaded. +* The planner doesn't combine multiple property index seeks when generating the results for the dynamic part of the query. For example, using `$any` in combination with multiple labels that share an index on a property result in the operator choosing one of the indexes based on selectivity and then stepping through the seek results and filtering for the remainder of the expression. ++ Example: ++ +[source, cypher, role=test-skip] +---- +CREATE RANGE INDEX actor_has_birthyear FOR (a:Actor) ON (a.birthYear) +CREATE RANGE INDEX director_has_birthyear FOR (d:Director) ON (d.birthYear) + +// The below MATCH can leverage one of the indexes, but not both +MATCH (p:$any(["Actor", "Director"]) { birthYear: 1983 }) RETURN p.name +---- + |=== [[further-reading]] diff --git a/modules/ROOT/pages/clauses/merge.adoc b/modules/ROOT/pages/clauses/merge.adoc index 6e20bd3f6..3d43b6a4e 100644 --- a/modules/ROOT/pages/clauses/merge.adoc +++ b/modules/ROOT/pages/clauses/merge.adoc @@ -750,13 +750,20 @@ The table below outlines performance caveats for specific Neo4j versions. | Neo4j versions | Performance caveat | 5.26 -- 2025.07 -| 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. +| 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. -| 2025.08 -- current +| 2025.08 -- 2025.10 | 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. 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`]. It is not, however, able to use indexes on property values. For example, `MERGE (n:$(Label) {foo: bar})` will not use any indexes on `n.foo` but can use a `DynamicLabelNodeLookup` on `$(label)`. +| 2025.11 -- current +a| The Cypher planner is able to leverage indexes on property values, however: + +* It only supports exact seeks on range indexes (no full text or spatial). +* The index order cannot be leveraged, so the planner must insert separate ordering if required later on in the query. +* Parallel runtime seeks and scans are single-threaded. + |=== \ No newline at end of file diff --git a/modules/ROOT/pages/deprecations-additions-removals-compatibility.adoc b/modules/ROOT/pages/deprecations-additions-removals-compatibility.adoc index ab35de6ee..975ca2a87 100644 --- a/modules/ROOT/pages/deprecations-additions-removals-compatibility.adoc +++ b/modules/ROOT/pages/deprecations-additions-removals-compatibility.adoc @@ -59,6 +59,33 @@ a| Both are similar to the `Merge` operator, but: * xref:planning-and-tuning/operators/operators-detail.adoc#query-plan-merge-into[`MergeInto`] is used when the start and end node of the pattern is matched outside the `MERGE` pattern; * xref:planning-and-tuning/operators/operators-detail.adoc#query-plan-merge-unique-node[`MergeUniqueNode`] is used when there is a property uniqueness constraint on the property used in the `MERGE` statement. +a| +label:functionality[] +label:updated[] + +[source, csv] +---- +// people.csv +label,name +Actor,Henry Cavill +---- + +[source, cypher, role=test-skip] +---- +CREATE RANGE INDEX actor_has_name FOR (a:Actor) ON (a.name); + +LOAD CSV WITH HEADERS FROM 'people.csv' AS row +// The MERGE below can leverage the index to check for existence before a CREATE +MERGE (:$(row.label) { name: row.name }) +---- + +a| Cypher can now leverage indexes on property values, improving the performance of xref:clauses/match.adoc#dynamic-match-caveats[`MATCH`] and xref:clauses/merge.adoc#dynamic-merge-caveats[`MERGE`] when doing so, however: + +* It only supports exact seeks on range indexes (no full text or spatial). +* The index order cannot be leveraged, so the planner must insert separate ordering if required later on in the query. +* Parallel runtime seeks and scans are single-threaded. +* The planner doesn't combine multiple property index seeks when generating the results for the dynamic part of the query. + |=== diff --git a/package-lock.json b/package-lock.json index 9f79f9220..5145dbdb1 100644 --- a/package-lock.json +++ b/package-lock.json @@ -373,9 +373,9 @@ "license": "MIT" }, "node_modules/@neo4j-antora/roles-labels": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/@neo4j-antora/roles-labels/-/roles-labels-0.1.2.tgz", - "integrity": "sha512-ruMZvGRxD3WyFVK/GaAO7gmNnU9zHuzfSbRpCMFJTasv78qRInn1np6WmTHZPbqynBWD3uYkh4pzIutBdJ8WFg==", + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/@neo4j-antora/roles-labels/-/roles-labels-0.1.4.tgz", + "integrity": "sha512-qNgUhWaD8zfGQmDwwmpkGTOXg8xnq7hv29Fz0mLV/KEh2+pcqQpPHIPlvCQIOEUlOFu2cp74xev/472A3B3tYA==", "license": "MIT", "dependencies": { "node-html-parser": "^7.0.0" @@ -1718,9 +1718,9 @@ } }, "node_modules/iconv-lite": { - "version": "0.7.0", - "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.7.0.tgz", - "integrity": "sha512-cf6L2Ds3h57VVmkZe+Pn+5APsT7FpqJtEhhieDCvrE2MK5Qk9MyffgQyuxQTm6BChfeZNtcOLHp9IcWRVcIcBQ==", + "version": "0.7.1", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.7.1.tgz", + "integrity": "sha512-2Tth85cXwGFHfvRgZWszZSvdo+0Xsqmw8k8ZwxScfcBneNUraK+dxRxRm24nszx80Y0TVio8kKLt5sLE7ZCLlw==", "dev": true, "license": "MIT", "dependencies": {