我们正在使用 apoc 插件从 Neo4j 数据库中删除节点,但观察到内存使用率很高。我们看到临时内存被删除,但在我们的例子中没有发生。我们使用的是社区版,所以我们无法诊断太多。
我为此打开了一个问题。
"CALL
apoc.periodic.iterate("MATCH (cl:Node1 {id: '" + label1 + "'}) -[:BELONGS]-> (c) return c","DETACH DELETE c",
{ batchSize: " + deleteBatchSize + ", parallel: " + deleteParallelCheck + ", concurrency: " + deleteConcurrencySize + ", retries: " + deleteRetriesAttempts + " })"
以下是相同的参数:
delete.parallel.check=true
delete.batch.size=2000
delete.concurrency.size=20
delete.retries.attempts=3
根据您的用例,一旦批次开始工作,其事务就会阻塞所有其他批次,直到完成。因此,并行执行查询是没有意义的,因为它会消耗大量资源,但不会为您带来任何好处。
每当事务删除关系时,就会在关系及其结束节点上放置写锁(因为它们都必须以某种方式进行修改)。这会阻止其他事务更新相同的实体。
在您的用例中,
DETACH DELETE c
删除c
节点及其BELONGS
关系。但是要删除的所有BELONGS
关系都连接到同一个cl
节点(假设Node1
节点具有唯一的id
值)。
因此,一旦批处理(事务)开始删除关系,它就会对单个共享
cl
施加写入锁定,并且所有其他批处理都必须等待(并占用内存),直到第一个批处理完成并释放写入锁定cl
。然后场景就会重复。
并非所有用例都适合并行化。
不要并行执行查询。只需直接执行类似这样的操作(其中
$id1
作为 参数 传递):
MATCH (:Node1 {id: $id1})-[:BELONGS]->(c)
DETACH DELETE c
[更新]
如果有许多
c
节点要删除,则上述查询可能会耗尽内存,因为所有操作都是在单个事务中完成的。
为了避免这种情况,您可以使用 apoc.periodic.iterate 批量执行删除(根据您的情况使用适当的批量大小):
CALL apoc.periodic.iterate(
"MATCH (:Node1 {id: $id1})-[:BELONGS]->(c)",
"DETACH DELETE c",
{batchSize: 5000})
parallel
配置参数默认为 false
,以避免写锁定阻塞问题。