索引查询恶化查询性能

Index queries worsen query performance

我试图在我的一个查询上使用索引以使其 运行 更快,但它使另一个查询 运行 变慢。所以我有一个数据处理查询?其中 运行 使用索引更快,另一个用于从 Neo4j(使用 Kafka)生成数据并开始使用索引 运行 变慢。我在数据处理之前创建索引,并在需要生成数据时删除它,但这不是一种有效的技术。 Neo4j 如何使用索引实际查询 运行 变慢?

这里是数据制作的查询:

 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: m.lon, latitude: m.lat}),point({ longitude: v.lon, latitude: v.lat })) < 4000 
RETURN distinct mt.member_id as member_id, m.lat as member_lat, m.lon as member_lon

没有索引的查询性能:

6432058 次 1888 毫秒内的数据库总命中数

带索引的查询的分析计划:

149617 毫秒内总数据库命中数为 138425061

索引查询如下所示:

  CREATE INDEX ON:MemberTopics(member_id)

  CREATE INDEX ON:MemberTopics(topic_id)

  CREATE INDEX ON:GroupTopics(topic_id)

索引查询性能较差的原因是 Cypher 规划器错误地计算了它承诺的工作量(估计行数与实际行数)。

在没有索引的情况下,规划器知道它必须对 MemberTopics 进行标签扫描,并且内部统计表明这将达到约 300 万行(这是正确的)。有了 Membertopics 上的索引,规划器的内部统计表明,如果使用该索引,它可能需要 ~2k 行,而实际结果是 ~7000 万行……哎呀!这部分是因为规划器低估了在查询的此时要处理的行数,但我不能确定为什么它会偏离这么多数量级。如果您从密码中删除成员节点并将 return 更改为 RETURN *,看起来您会得到该问题的答案。


这部分是因为您的 cypher/data 本身就是一个需要计划的怪物。

  • 您匹配了 2 个未在别处使用的主题节点(t 和 t1)
  • WHERE mt.topic_id = gt.topic_id 是一个 foreign key 引用,永远不应该出现在密码中;这真的是你表现糟糕的关键。 topic_id 应该是它自己的节点,或者你应该在 mt 和 gt 之间有直接关系。 Neo4j 非常擅长走关系边缘。外键很糟糕(与处理关系相比)。
    • 你有 2 条长路径,没有明确说明它们之间的关系(从 Cypher 规划者的角度来看)。
  • 你的 MATCH 是一对没有明确起点的长路径链。不将其中一个节点锁定到特定(少数)节点的长路径几乎肯定会激增您的查询行数,从而激增您的性能。

至于你能做些什么,

  • 限制查询范围

对单个成员、组或区域

  • 使用 WITH
  • 将您的查询分成多个阶段

With 创建了 Cypher 的逻辑分区,规划器将主要尝试解决 WITH 之前的所有问题,然后再继续其余的逻辑。您比计划员更了解您的数据,因此这是在不更改结果的情况下限制查询范围的好方法。 (在你的情况下,可能只从 Member 和 Venue 开始,然后从那里过滤。)

  • 不要使用外键

用关系或中间节点替换mt.topic_id = gt.topic_id