我想在执行递归查询时比较Neo4j( ver.3.1 )和MySQL。因此,我在MySQL数据库中创建了两个表 - Customer
和CustomerFriend
。
第二个表包含CustomerID
和FriendID
列,它们都指向CustomerID
表中的Customer
列。在Neo4j中创建了相应的实体:
Customer
个节点和FRIEND_OF
个关系(c:Customer)-[f:FRIEND_OF]->(cc:Customer)
。数据库填充相同的数据:
100000个客户,每个客户有100个关系。
执行以下查询:
MySQL( 60s )
SELECT distinct cf4.FriendID FROM customerfriend cf1
join customerfriend cf2 on cf1.FriendID = cf2.CustomerID
join customerfriend cf3 on cf2.FriendID = cf3.CustomerID
join customerfriend cf4 on cf3.FriendID = cf4.CustomerID
where cf1.CustomerID =99;
Neo4j( 240s )
match (c:Customer{CustomerID:99})-[:FRIEND_OF*4]->(cc:Customer)
return distinct cc.CustomerID;
查询从简单的Java应用程序运行,该应用程序只连接到数据库(使用可用的连接器),运行查询和测量执行时间。
测量时间清楚地表明Neo4j执行上述查询的速度比MySQL(MySQL 60s,Neo4j 240s)慢。我已经测试了每个客户50个关系的上述查询,并且我获得了相同的结果(MySQL 7s 比Neo4j 17s 更快)。
我阅读了一些关于在Neo4j中执行递归查询的文章,这些文章表明Neo4j应该比MySQL更好地管理这类查询。这就是为什么我开始怀疑自己是做错了什么的 执行时间是正确的( ?? )。
我想知道在Neo4j中是否存在调整系统性能的任何可能性。在MySQL的情况下,我将innodb_buffer_pool_size
设置为3g,这会影响更好的查询性能(更短的执行时间)。
-------------------------------- 修改 ------- --------------------
我考虑过以下建议将Noe4j查询重写为新表单:
match (c:Customer{CustomerID:99})-[:FRIEND_OF]->(c1)-[:FRIEND_OF]->(c2)
with distinct c2
match (c2)-[:FRIEND_OF]->(c3)
with distinct c3
match (c3)-[:FRIEND_OF]->(cc:Customer)
with distinct cc
return cc.CustomerID;
获得更好的查询时间: 40s
在MySQL的情况下,我已经找到了优化先前查询的方法,类似于Neo4j查询优化的想法:
select distinct FriendID as depth4
from customerfriend
where CustomerID in
(select distinct FriendID as depth3
from customerfriend
where CustomerID in
(select distinct FriendID as depth2
from customerfriend
where CustomerID in
(select distinct FriendID as depth
from customerfriend
where CustomerID =99
)));
此查询的执行需要 24s
Neo4j仍然比MySQL差......
答案 0 :(得分:3)
你可以尝试:
match (c:Customer{CustomerID:99})-[:FRIEND_OF]->(c1)-[:FRIEND_OF]->(c2)
with distinct c2
match (c2)-[:FRIEND_OF]->(c3)
with distinct c3
match (c3)-[:FRIEND_OF]->(cc)
with distinct cc
return cc.CustomerID;
并分享您的查询计划和此查询的查询计划?
要仅测量没有电汇的查询时间,您可以尝试运行这个:
match (c:Customer{CustomerID:99})-[:FRIEND_OF]->(c1)-[:FRIEND_OF]->(c2)
with distinct c2
match (c2)-[:FRIEND_OF]->(c3)
with distinct c3
match (c3)-[:FRIEND_OF]->(cc)
with distinct cc
with cc.CustomerID
return count(*);
答案 1 :(得分:3)
您可以进行一些小修改,使neo4j的速度提高约50%,或者为了更快的速度,使用此博客文章底部显示的bitset dance => https://maxdemarzi.com/2013/12/31/the-power-of-open-source-software/
<强>更新强>
我继续为你建立了一个自定义程序。
您可以在https://github.com/maxdemarzi/distinct_network
的发布标签中抓取它我的笔记本电脑需要2.9秒才能获得10002045关系。
第二次更新:
写了一篇关于这个主题的博文:https://maxdemarzi.com/2017/02/06/neo4j-is-faster-than-mysql-in-performing-recursive-query/
答案 2 :(得分:0)
不知道你正在运行什么版本的Neo4j,但这可能会提高你的速度,同时减少db命中率:
MATCH (c:Customer{CustomerID:99})
MATCH (c)-[:FRIEND_OF*4]->(cc:Customer)
return distinct cc.CustomerID;
答案 3 :(得分:0)
我建议为此安装APOC Procedures,Path Expander功能是一种在路径上查找节点的更有效方法,无需额外花费查找所有可能的路径。
match (c:Customer{CustomerID:99})
call apoc.path.expandConfig(c, {relationshipFilter:"FRIEND_OF>", minLevel:4, maxLevel:4}) yield path
with distinct last(nodes(path)) as cc
where cc:Custumer
return cc.CustomerID
修改
在这种情况下,NODE_GLOBAL唯一性看起来不起作用。我通常在获取子图中的所有节点时使用它,但它不适用于此特定情况并将其删除以使用默认唯一性设置。
不确定这与等效的可变长度模式匹配的比较。数据库命中率会降低,因为过程调用仅计为一次数据库命中并抽象出它正在进行的工作,但不确定它是否更快。