赞
踩
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 |
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。