我正在使用 Neo4j 并遇到特定查询结构的超时问题。我有两个查询看起来非常相似,但在性能方面产生不同的结果。
以下是疑问:
这个按预期工作并返回所需的结果:
MATCH (selected_method:Method{name:$neodash_method_name, class_name:$neodash_class_name, module_name:$neodash_module_name})
MATCH (others:Method)-[all*]->(selected_method)
RETURN *
但是,以下查询超时:
MATCH (selected_method:Method{name:$neodash_method_name, class_name:$neodash_class_name, module_name:$neodash_module_name})
MATCH (selected_method)<-[all*]-(others:Method)
RETURN *
我希望这两个查询具有相似的性能。
发生的事情有什么解释吗?
我使用了
EXPLAIN
命令,它为两个查询返回了相同的执行计划:
Planner COST
Runtime PIPELINED
Runtime version 5.20
Batch size 1024
+------------------------+----+------------------------------------------------------------------------------------------------------+----------------+---------------------+
| Operator | Id | Details | Estimated Rows | Pipeline |
+------------------------+----+------------------------------------------------------------------------------------------------------+----------------+---------------------+
| +ProduceResults | 0 | all, others, selected_method | 109067277 | |
| | +----+------------------------------------------------------------------------------------------------------+----------------+ |
| +VarLengthExpand(Into) | 1 | (others)-[all*]->(selected_method) | 109067277 | Fused in Pipeline 3 |
| | +----+------------------------------------------------------------------------------------------------------+----------------+---------------------+
| +CartesianProduct | 2 | | 67222 | In Pipeline 2 |
| |\ +----+------------------------------------------------------------------------------------------------------+----------------+---------------------+
| | +NodeByLabelScan | 3 | others:Method | 23190 | In Pipeline 1 |
| | +----+------------------------------------------------------------------------------------------------------+----------------+---------------------+
| +Filter | 4 | (selected_method.name = $neodash_method_name AND selected_method.class_name = $neodash_class_name AN | 3 | |
| | | | D selected_method.module_name = $neodash_module_name) | | |
| | +----+------------------------------------------------------------------------------------------------------+----------------+ |
| +NodeByLabelScan | 5 | selected_method:Method | 23190 | Fused in Pipeline 0 |
+------------------------+----+------------------------------------------------------------------------------------------------------+----------------+---------------------+
Total database accesses: ?
Planner COST
Runtime PIPELINED
Runtime version 5.20
Batch size 1024
+------------------------+----+------------------------------------------------------------------------------------------------------+----------------+---------------------+
| Operator | Id | Details | Estimated Rows | Pipeline |
+------------------------+----+------------------------------------------------------------------------------------------------------+----------------+---------------------+
| +ProduceResults | 0 | all, others, selected_method | 109067277 | |
| | +----+------------------------------------------------------------------------------------------------------+----------------+ |
| +VarLengthExpand(Into) | 1 | (selected_method)<-[all*]-(others) | 109067277 | Fused in Pipeline 3 |
| | +----+------------------------------------------------------------------------------------------------------+----------------+---------------------+
| +CartesianProduct | 2 | | 67222 | In Pipeline 2 |
| |\ +----+------------------------------------------------------------------------------------------------------+----------------+---------------------+
| | +NodeByLabelScan | 3 | others:Method | 23190 | In Pipeline 1 |
| | +----+------------------------------------------------------------------------------------------------------+----------------+---------------------+
| +Filter | 4 | (selected_method.name = $neodash_method_name AND selected_method.class_name = $neodash_class_name AN | 3 | |
| | | | D selected_method.module_name = $neodash_module_name) | | |
| | +----+------------------------------------------------------------------------------------------------------+----------------+ |
| +NodeByLabelScan | 5 | selected_method:Method | 23190 | Fused in Pipeline 0 |
+------------------------+----+------------------------------------------------------------------------------------------------------+----------------+---------------------+
Total database accesses: ?
我也尝试过使用不同的运行时设置,但第二个查询始终导致超时。
这两个查询代表相同的事物,并且会产生相同的结果。我们知道写作(s)<-[*]-(o) means the same thing as writing (o)-[*]->(s)。正如您所写,查询计划是相同的,具有相同的运算符和基数估计。
但是,获得结果的过程可能有所不同。您会看到 VarLengthExpand(Into) 运算符的详细信息因模式写入的方向而异(就像在查询中一样)。当进行 VarLength 扩展时,查询运行时必须决定从一个节点开始扩展,并且从哪里开始可能取决于它的写入顺序(至少我认为可以)。根据图形结构,从一个开始时可能是一个快速操作,但从另一个开始时可能会很大。
想象一下,如果 (o) 仅与 (s) 有单一连接,而 (s) 与所有事物都有连接。如果你现在从 (o) 开始,你将遵循一个关系,找到 (s) 并知道你已经完成了,而如果你从 (s) 开始,你将必须遍历所有内容,然后才能知道它与 (o) 仅有一个连接).
现在,还有更多内容,例如图的统计数据和基数估计,在本例中 (s) 和 (o) 之间非常不同。所以我不能肯定地说情况就是如此,但是编写查询的顺序会影响运行所需的时间,或者即使它是可解决的,即使最终结果是相同的。
现在,尽管如此,这也可能是由于查询执行中的某些问题造成的。在不知道图表是什么样子的情况下,它似乎应该知道最好从哪里开始。看起来你在 5.20 上运行,我建议你尝试升级到最新版本(目前是 5.25.1)并尝试那里,它可能会解决它(如果你在 Aura 上,你已经在 5.25 上) .1 因此您无需执行任何操作,只需重试即可)。