neo4j--Cypher查询调优与执行计划

1.查询调优

1.1查询如何执行

Cypher执行引擎会将每个Cypher查询都转为一个执行计划。在执行查询时,执行计划将告知Neo4j执行什么样的操作。

1.2查询性能分析

查看执行计划对查询进行分析时有两个Cypher语句可用:

1.2.1 EXPLAIN

如果只想查看查询计划,而不想运行该语句,可以在查询语句中加入EXPLAIN。此时,该语句将返回空结果,对数据库不会做出任何改变。

1.2.2 PROFILE

如果想运行查询语句并查看哪个运算符占了大部分的工作,可以使用PROFILE此时,该语句将被运行,并跟踪传递了多少行数据给每个运算符,以及每个运算符与存储层交互了多少以获取必要的数据。注意,加入PROFILE的查询语句将占用更多的资源,所以除非真正在做性能分析,否则不要使用PROFILE。

1.3查询调优举例

写一个找到'Tom Hanks'的查询语句。比较初级的做法是按如下方式写:

MATCH (p { name: 'Tom Hanks' })

RETURN p

这个查询将会找到'Tom Hanks'节点,但是随着数据库中节点数的增加,该查询将越来越慢。可以通过使用PROFILE来找到原因。

PROFILE

MATCH (p { name: 'Tom Hanks' })

RETURN p

首先需要记住的是,查看执行计划应该从底端往上看。在这个过程中,我们注意到从最后一行开始的Rows列中的数字远高于给定的name属性为'Tom Hanks'的一个节点。在Operator列中我们看到AllNodeScan被使用到了,这意味着查询计划器扫描了数据库中的所有节点。

 向上移动一行看Filter运算符,它将检查由AllNodeScan传入的每个节点的name属性。这看起来是一种非常低效的方式来查找'Tom Hanks'。

 解决这个问题的办法是,无论什么时候我们查询一个节点,都应该指定一个标签来帮助查询计划器缩小搜索空间的范围。对于这个查询,可简单地添加一个Person标签。

PROFILE

MATCH (p:Person { name: 'Tom Hanks' })

RETURN p

这次最后一行Rows的值已经降低了,这里没有扫描到之前扫描到的那些节点。NodeByLabelScan运算符表明首先在数据库中做了一个针对所有Person节点的线性扫描。一旦完成后,后续将针对所有节点执行Filter运算符,依次比较每个节点的name属性。

这在某些情况下看起来还可以接受,但是如果频繁通过name属性来查询Person,针对带有Person标签的节点的name属性创建索引将获得更好的性能。

CREATE INDEX ON :Person(name)

现在再次运行该查询将运行得更快。

PROFILE

MATCH (p:Person { name: 'Tom Hanks' })

RETURN p

查询计划下降到单一的行并使用了NodeIndexSeek运算符,它通过模式索引寻找到对应的节点。

1.4 USING语句

当执行一个查询时,Neo4j需要决定从查询图中的哪儿开始匹配。这是通过查看MATCH语句和WHERE中的条件这些信息来找到有用的索引或者其他开始节点。

然而,系统选定的索引未必总是最好的选择。

 可以通过USING来强制Neo4j使用一个特定的开始点。这个被称为计划器提示。这里有三种类型的计划器提示:索引提示,扫描提示和连接(join)提示。

1.4.1索引提示

索引提示用于告知计划器无论在什么情况下都应使用指定的索引作为开始点。对于某些特定值的查询,索引统计信息不准确,它可能导致计划器选择了非最优的索引。对于这种情况,索引提示就有它的用处。使用在MATCH语句之后添加USING INDEX variable:Label(property)来补充索引提示。

也可以补充多个索引提示,但是多个开始点会在后面的查询计划中潜在地需要额外的连接。

使用索引提示查询

上面的查询没有选择索引来生成计划。这是因为图非常小,对于小数据库标签扫描很快。然而,查询的性能通常以dbhit的值来度量。下面可以看到使用索引将获得更好的查询性能。

PROFILE

MATCH (p:Person { name: 'Tom Hanks' })

USING INDEX p: Person (name)

RETURN p.born AS column

使用多个索引提示查询

PROFILE

MATCH (p:Person { name: 'Tom Hanks' })-[r]->( m:Movie {title:"You've Got Mail"

})

USING INDEX p: Person (name)

USING INDEX m: Movie (title)

RETURN p.born AS column

使用稍微更好的计划返回'Barbara Liskov'的出生年。

1.4.2 扫描提示

如果查询匹配到一个索引的大部分,它可以更快地扫描标签并过滤掉不匹配的节点。通过在MATCH语句后面使用USING SCAN variable:Label可以做到这一点。它将强制Cypher不使用本应使用的索引,而采用标签扫描。

标签扫描提示

使用USING SCAN扫描一个标签上的所有节点并过滤结果集将获得最好的性能。

<

PROFILE

MATCH (s: Person)

USING SCAN s: Person

WHERE s.born < 1939

RETURN s.born AS column

  • 4
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值