【问题标题】:Improve Neo4j query performance提高 Neo4j 查询性能
【发布时间】:2018-07-20 12:02:21
【问题描述】:

我有一个包含多个实体的 Neo4j 查询,我想使用节点对象批量传递参数。但是,我的查询执行速度不是很高。如何优化此查询并使其性能更好?

WITH $nodes as nodes
    UNWIND nodes AS node
      with node.id AS id, node.lon AS lon, node.lat AS lat
    MATCH 
    (m:Member)-[mtg_r:MT_TO_MEMBER]->(mt:MemberTopics)-[mtt_r:MT_TO_TOPIC]->(t:Topic),
    (t1:Topic)-[tt_r:GT_TO_TOPIC]->(gt:GroupTopics)-[tg_r:GT_TO_GROUP]->(g:Group)-[h_r:HAS]->
    (e:Event)-[a_r:AT]->(v:Venue) 
    WHERE mt.topic_id = gt.topic_id AND 
    distance(point({ longitude: lon, latitude: lat}),point({ longitude: v.lon, latitude: v.lat })) < 4000 AND 
    mt.member_id = id
RETURN 
    distinct id as member_id, 
    lat as member_lat, 
    lon as member_lon, 
    g.group_name as group_name, 
    e.event_name as event_name, 
    v.venue_name as venue_name, 
    v.lat as venue_lat, 
    v.lon as venue_lon, 
    distance(point({ longitude: lon, 
    latitude: lat}),point({ longitude: v.lon, latitude: v.lat })) as distance

查询分析如下所示:

【问题讨论】:

  • 你的索引是什么?一个直接的建议是索引mt.member_id,然后先进行匹配,然后将其放入 with 子句中,然后匹配其余部分。这将减少相当多的工作量。 3000 万的“NodeByLabelScan”可能是最痛苦的。另外,为什么要将一个节点中的 ID 与另一个节点中的 ID 匹配?为什么这些节点之间没有关系?如果您可以创建它们,它也会变得更快。
  • t 和 t1 假设是同一个主题节点吗?如果是这样,你为什么要在那里分割查询?同时在(mt:MemberTopics) mt.id 上放置一个索引并内联规划器(mt:MemberTopics {id:id}) 的id 匹配,将把该部分从30mill db hits 减少到~1db hits。另外,您能否将其他框也展开,以便我们可以看到它们在做什么?
  • 匹配 MemberTopics 之后,距离搜索可能是下一个最昂贵的部分,但是一旦规划器可以在 1db 命中获得 MemberTopic,距离查找应该会快得多(因为它不会尝试并行执行,但仅在 mt 实际连接的节点上)
  • @Tezra 谢谢!创建索引和匹配 id 确实有助于提高性能!您可以将其发布为答案吗?
  • @Tezra 另外,我删除了查询中的拆分,它开始工作得更快。我首先使用了拆分,因为没有它,查询不会返回任何结果

标签: neo4j cypher graph-databases neo4j-apoc


【解决方案1】:

所以,您当前的计划有 3 个并行线程。我们现在可以忽略一个,因为它有 0db 的命中率。

您受到的最大打击是匹配(mt:MemberTopics) ... WHERE mt.member_id = id。我猜 member_id 是一个唯一的 id,所以你会想在它上面创建一个索引CREATE INDEX ON :MemberTopics(member_id)。这将允许 Cypher 进行索引查找而不是节点扫描,这会将数据库命中率从 ~30mill 减少到 ~1(此外,在某些情况下,对于更复杂的查询,内联属性匹配更快。所以(mt:MemberTopics {member_id:id})更好。它明确地表明这个条件在匹配时必须始终为真,并且会加强使用索引查找)

第二大打击是点距离检查。现在,这是独立完成的,因为节点扫描需要很长时间。一旦您对 MemberTopic 进行了更改,规划者应该切换到查找所有连接的场地,然后只对 thous 进行距离检查,这样也会变得更便宜。

另外,看起来 mt 和 gt 是由一个主题链接的,而您正在使用主题 id 来对齐它们。如果假设 t 和 t1 是同一个 Topic 节点,您可以只对两个节点使用 t 来强制执行此操作,然后您不需要进行 id 检查来链接 mt 和 gt。如果 t 和 t1 不是同一个节点,则在节点属性中使用外键表示您应该在两个节点之间建立关系,并且沿着该边移动(关系也可以具有属性,但上下文看起来很像 t 和 t1 应该是同一个节点。您也可以通过说 WHERE t = t1 来强制执行此操作,但此时您应该对两个节点都使用 t)

最后,根据查询返回的行数,您可能希望使用 LIMIT 和 SKIP 对结果进行分页。这看起来像是发送给用户的信息,我怀疑他们需要完整的转储。所以只返回最上面的结果,如果用户想看更多,只处理其余的。 (当结果接近一公吨时很有用)由于到目前为止您只有 21 个结果,因此现在这不是问题,但请记住,您需要扩展到 100,000 多个结果。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2013-08-03
    • 1970-01-01
    • 1970-01-01
    • 2021-08-03
    • 2013-02-17
    • 2021-12-15
    • 2014-04-09
    相关资源
    最近更新 更多