From af38290f8b36a1455ced4896c1e6ff175d90f3a0 Mon Sep 17 00:00:00 2001 From: Henrik Nyman Date: Wed, 11 Jun 2025 11:16:39 +0200 Subject: [PATCH 1/2] Add best practice example to subqueries in transactions with deadlocks section (#1301) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Jens Pryce-Ã…klundh <112686610+JPryce-Aklundh@users.noreply.github.com> --- .../subqueries-in-transactions.adoc | 49 ++++++++++++++++++- 1 file changed, 48 insertions(+), 1 deletion(-) diff --git a/modules/ROOT/pages/subqueries/subqueries-in-transactions.adoc b/modules/ROOT/pages/subqueries/subqueries-in-transactions.adoc index 9af386cbb..7e48894a7 100644 --- a/modules/ROOT/pages/subqueries/subqueries-in-transactions.adoc +++ b/modules/ROOT/pages/subqueries/subqueries-in-transactions.adoc @@ -956,7 +956,7 @@ CALL (row) { MERGE (y:Year {year: row.year}) MERGE (m)-[r:RELEASED_IN]->(y) } IN 2 CONCURRENT TRANSACTIONS OF 10 ROWS ON ERROR RETRY FOR 3 SECONDS THEN CONTINUE REPORT STATUS AS status -RETURN status.transactionID as transaction, status.committed AS successfulTransaction +RETURN status.transactionId as transaction, status.committed AS successfulTransaction ---- // end::subqueries_in_transactions_deadlock_example[] @@ -1064,6 +1064,53 @@ The result shows that all transactions are now successful: +-------------------------------------------------+ ---- +Deadlock resolution and transaction retries are time-consuming, making deadlock avoidance a preferred strategy. +This can be achieved by dividing a task into two distinct subqueries: a data-independent subquery run in parallel with maximum concurrency, and a data-dependent subquery executed serially (i.e. one transaction at a time) to avoid deadlocks. +In the below example, nodes and properties are created in a concurrent subquery, while the relationships connecting those nodes are created in a serial subquery. +This method benefits from the performance of concurrent transactions while avoiding deadlocks. + +.Avoiding deadlocks by dividing an import task into a data-independent concurrent subquery followed by a data-dependent serial subquery +// tag::subqueries_in_transactions_deadlock_example_2[] +[source, cypher] +---- +LOAD CSV WITH HEADERS FROM 'https://data.neo4j.com/importing-cypher/movies.csv' AS row +CALL (row) { + MERGE (m:Movie {movieId: row.movieId}) + MERGE (y:Year {year: row.year}) + RETURN m, y +} IN CONCURRENT TRANSACTIONS OF 10 ROWS ON ERROR RETRY THEN CONTINUE REPORT STATUS AS nodeStatus +CALL (m, y) { + MERGE (m)-[r:RELEASED_IN]->(y) +} IN TRANSACTIONS OF 10 ROWS ON ERROR RETRY THEN CONTINUE REPORT STATUS AS relationshipStatus +RETURN nodeStatus.transactionId as nodeTransaction, + nodeStatus.committed AS successfulNodeTransaction, + relationshipStatus.transactionId as relationshipTransaction, + relationshipStatus.committed AS successfulRelationshipTransaction +---- +// end::subqueries_in_transactions_deadlock_example_2[] + +.Click to see an example of failed transactions being retried without using `ON ERROR RETRY` +[%collapsible] +==== + +.Query retrying failed transactions +[source, cypher] +---- +LOAD CSV WITH HEADERS FROM 'https://data.neo4j.com/importing-cypher/movies.csv' AS row +CALL (row) { + MERGE (m:Movie {movieId: row.movieId}) + MERGE (y:Year {year: row.year}) + MERGE (m)-[r:RELEASED_IN]->(y) +} IN 2 CONCURRENT TRANSACTIONS OF 10 ROWS ON ERROR CONTINUE REPORT STATUS as status +WITH * +WHERE status.committed = false +CALL (row) { + MERGE (m:Movie {movieId: row.movieId}) + MERGE (y:Year {year: row.year}) + MERGE (m)-[r:RELEASED_IN]->(y) +} IN 2 CONCURRENT TRANSACTIONS OF 10 ROWS ON ERROR FAIL +---- +==== ===== [[restrictions]] From a4d2a8fc842ef944783efca0b750d9592d5aecf5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jens=20Pryce-=C3=85klundh?= <112686610+JPryce-Aklundh@users.noreply.github.com> Date: Wed, 11 Jun 2025 11:21:59 +0200 Subject: [PATCH 2/2] remove example --- .../subqueries-in-transactions.adoc | 22 ------------------- 1 file changed, 22 deletions(-) diff --git a/modules/ROOT/pages/subqueries/subqueries-in-transactions.adoc b/modules/ROOT/pages/subqueries/subqueries-in-transactions.adoc index 7e48894a7..93c2f6153 100644 --- a/modules/ROOT/pages/subqueries/subqueries-in-transactions.adoc +++ b/modules/ROOT/pages/subqueries/subqueries-in-transactions.adoc @@ -1089,28 +1089,6 @@ RETURN nodeStatus.transactionId as nodeTransaction, ---- // end::subqueries_in_transactions_deadlock_example_2[] -.Click to see an example of failed transactions being retried without using `ON ERROR RETRY` -[%collapsible] -==== - -.Query retrying failed transactions -[source, cypher] ----- -LOAD CSV WITH HEADERS FROM 'https://data.neo4j.com/importing-cypher/movies.csv' AS row -CALL (row) { - MERGE (m:Movie {movieId: row.movieId}) - MERGE (y:Year {year: row.year}) - MERGE (m)-[r:RELEASED_IN]->(y) -} IN 2 CONCURRENT TRANSACTIONS OF 10 ROWS ON ERROR CONTINUE REPORT STATUS as status -WITH * -WHERE status.committed = false -CALL (row) { - MERGE (m:Movie {movieId: row.movieId}) - MERGE (y:Year {year: row.year}) - MERGE (m)-[r:RELEASED_IN]->(y) -} IN 2 CONCURRENT TRANSACTIONS OF 10 ROWS ON ERROR FAIL ----- -==== ===== [[restrictions]]