Neo4j入门点滴(四):Cypher查询优化

简介:  首先,还是老样子,清楚当前数据库中所有的内容,干干净净开始学习新的一章。 match (n)-[r]-(n1) delete r,n,n1 match (n) delete n ...

 首先,还是老样子,清楚当前数据库中所有的内容,干干净净开始学习新的一章。
  1. match (n)-[r]-(n1)
  2. delete r,n,n1
  3. match (n)
  4. delete n
  接下来,还要使用第二篇博文中的人物和联系:
  1. CREATE (bradley:MALE:TEACHER {name:'Bradley', surname:'Green',age:24, country:'US'})
  2. CREATE (matthew:MALE:STUDENT {name:'Matthew', surname:'Cooper',age:36, country:'US'})
  3. CREATE (lisa:FEMALE {name:'Lisa', surname:'Adams', age:15,country:'Canada'})
  4. CREATE (john:MALE {name:'John', surname:'Goodman', age:24,country:'Mexico'})
  5. CREATE (annie:FEMALE {name:'Annie', surname:'Behr', age:25,country:'Canada'})
  6. CREATE (ripley:MALE {name:'Ripley', surname:'Aniston',country:'US'})
  7. MATCH (bradley:MALE{name:"Bradley"}),(matthew:MALE{name:"Matthew"})WITH bradley, matthew CREATE (bradley)-[:FRIEND]->(matthew) , (bradley)-[:TEACHES]->(matthew);
  8. MATCH (bradley:MALE{name:"Bradley"}),(matthew:MALE{name:"Matthew"})WITH bradley,matthew CREATE (matthew)-[:FRIEND]->(bradley);
  9. MATCH (bradley:MALE{name:"Bradley"}),(lisa:FEMALE{name:"Lisa"})WITH bradley,lisa CREATE (bradley)-[:FRIEND]->(lisa);
  10. MATCH (lisa:FEMALE{name:"Lisa"}),(john:MALE{name:"John"})WITH lisa,john CREATE (lisa)-[:FRIEND]->(john);
  11. MATCH (annie:FEMALE{name:"Annie"}),(ripley:MALE{name:"Ripley"})WITH annie,ripley CREATE (annie)-[:FRIEND]->(ripley);
  12. MATCH (ripley:MALE{name:"Ripley"}),(lisa:FEMALE{name:"Lisa"})WITH ripley,lisa CREATE (ripley)-[:FRIEND]->(lisa);


一、索引
  Neo4j2.0版本在标签的基础上引入了索引,可以对标签进行限制和索引。这种方式即有助于数据完整性检查,也有利于优化Cypher。上一篇博文最后介绍了限制,本篇关注度的则是索引的用法和功能  
  Neo4j的索引和其他RDBMS的定义相类似,主要用于提升节点找寻的性能。对于任何已有数据结构的更改操作 索引自动更新。如果出了错而导致索引处于无效状态,便需要差错并重新生成它们。
  Cypher查询会自动使用索引,Cypher有一个查询计划器和查询优化器,可以对 查询进行评估并尝试尽全力依据选索引择最短执行 时间。
  创建索引的过程并不复杂:
  首先,使用如下语句对标签MALE和属性name创建一个索引:
  1. create index on :MALE(name)
  核实是否已经创建,书上说需要在neo4j-shell中使用下列命令:schema ls。但我在Web界面上使用则是报错,没有此命令。
  删除索引使用如下命令:
  1. drop index on :MALE(name)
  一旦索引建立,随后 但凡在where从句中出现具有索引的属性时,不论是简单的等值比较还是其他条件, 索引的使用都是自动的 。然而,还有一种外显的指定索引的使用方式,就是using从句。如:
  1. create index on :MALE(name)
  2. match (n:MALE)
  3. using index n:MALE(name)
  4. where n.name = "Matthew"
  5. return n
  结果如下图所示,很遗憾在非终端中看不到查询的耗时,尽管目前的学习和测试是在Win 10下完成的,但也可以使用windows准备的Cypher-shell,可以参考另一篇文章《Neo4j入门点滴(五):Windows Shell for Cypher》。

  重点来了,必须记住:我们也可以在一个单一查询中 使用using从句并 提供多个索引项来 给Cypher Query Optimizer提供索引提示 ,也可以使用scan给Cypher Query Planner先扫描所有标签然后再执行后续的过滤,这种做法的结果意味着优秀的性能,毕竟使用标签本身可以不必考虑那些 不必要的数据。如:
  1. match (n:MALE)
  2. using scan n:MALE
  3. where n.name = "Matthew"
  4. return n
  尽管上述查询的结果是一样的,但性能会更好。需要注意的一点, 使用scan时使用的是:MALE,而非index时的:MALE(name ),这点一定要警惕。


、Index Sampling
  真不太好翻译,所以还是直接使用英文词组吧。
  其实,所有Cypher查询执行的第一步就是先要制订出一个有效的执行计划。尽管这个计划由Neo4j自行创建,但创建之前系统需要知道当前数据库、索引、索引所含的节点数、联系等多种重要信息。这些信息将帮助Neo4j设计一个效率高、效果好的执行计划,从而使得我们的查询请求被更快地响应。下一小节在详细讨论执行计划的过程,但是有效执行计划其中一个步骤就是Index Sampling。实际上,Index Sampling就是我们经常对索引进行分析和取样,确保索引统计数据更新,以及在数据库增删改数据的并对相应索引进行更改的全部过程。
  我们可以通过开启Neo4j数据库的下列属性实现自动index sampling(Linux下是文件neo4j.properties,windows的还没找到):
  • index_background_sampling_enabled:该布尔属性值默认被设置为False,将其改为True开启自动sampling。
  • index_sampling_update_percentage:定义了在触发sampling之前需要被改变索引的百分比阈值。
  当然,也可以在终端中输入如下命令 手动开启:
  • schema sample -a:触发对所有索引做sampling。
  • schema sample -l MALE -p name:仅仅触发标签(l)和属性(p)定义的索引的sampling。

三、理解执行计划
  对于所有查询的执行计划的生成,Neo4j使用的都是基于成本的优化器(Cost Based Optimizer,CBO),用于制订精确的执行过程。可以采用如下两种不同的方式了解其内部的工作机制:
  • EXPLAIN:是解释机制,加入该关键字的Cypher语句可以预览执行的过程但并不实际执行,所以也不会产生任何结果。
  • PROFILE:则是画像机制,查询中使用该关键字,不仅能够看到执行计划的详细内容,也可以看到查询的执行结果。
  举例如下:
  1. profile match (n)
  2. where n.name = 'Annie'
  3. return n
  如下图所示:

  点击展开后,是这样:

  此外,我还发现,Shell模式下,explain和profile都不如Web界面输入的信息多,不知道是不是版本的问题,还是参数设置的问题:



、分析并优化查询
  还是用刚才Annie那个例子,正如所见,原查询并不高效,因为AllNodesScan需要对所有节点逐一进行匹配。然而,别忘了,Cypher引入的标签系统可不是摆着看的,试着对刚才的例子添加标签:
  1. profile match (n:FEMALE)
  2. where n.name = 'Annie'
  3. return n
  结果如下图:

  可以看到,优化器由AllNodesScan变为了NodeByLabelScan,过滤的过程也有原来的6-1-1缩减为当前的2-1-1。但这并没有结束,还可以进一步优化,对,就是使用index。
  1. create index on :FEMALE(name)
  其他都不变,只是提前创建一条索引,这下子优化器就可以用NodeIndexSeek,整个过程由刚才的2-1-1变成了现在的1-1-1,也就是没有任何不必要的额外付出,一击命中!
  具体的优化参数,可以参考estimated rows和db hits这两个数值,都是越小越好。前者指需要被扫描行数的预估值 后者是系统实际运行结果的 命中(I/O)绩效。其实,并不存在放之四海而皆准的通用标准(否则开发者 已经就直接把这些标准内化到Neo4j中了 ),所以还需要积累经验,经常对Cypher的 执行进行分析和优化。



五岳之巅             
2017年5月29日(孟菲斯时间)
09:10
终稿于Dorsy Ave, Memphis, TN

相关文章
|
SQL NoSQL MySQL
MongoDB 执行计划 & 优化器简介 (上)
最近,由于工作需求去了解一下Query是如何在MongoDB内部进行处理,从而丢给存储引擎的。里面涉及了Query执行计划和优化器的相关代码,MongoDB整体思路设计的干净利落,有些地方深入挖一下其实还是能有些优化点的。本文会涉及一条Query被parse之后一路走到引擎之前,都做了那些事情,分析基于MongoDB v3.4.6代码。由于篇幅过长,文章分为上下两篇,分别介绍执行计划 & 优化器和
3617 0
|
6月前
|
SQL 关系型数据库 MySQL
MySQL高级【多表查询】第九章(下)
MySQL高级【多表查询】第九章
|
6月前
|
SQL 关系型数据库 MySQL
MySQL高级【多表查询】第九章(上)
MySQL高级【多表查询】第九章
|
9月前
|
存储 SQL 缓存
MySQL高级第二篇(共四篇)之体系结构、存储引擎、优化SQL步骤、索引使用、SQL优化
最上层是一些客户端和链接服务,包含本地sock 通信和大多数基于客户端/服务端工具实现的类似于 TCP/IP的通信。主要完成一些类似于连接处理、授权认证、及相关的安全方案。在该层上引入了线程池的概念,为通过认证安 全接入的客户端提供线程。同样在该层上可以实现基于SSL的安全链接。服务器也会为安全接入的每个客户端验证它所具有的操作权限。
374 1
|
9月前
|
索引
EXPLAIN简介
EXPLAIN简介
38 0
|
SQL 数据库
数据库原理与应用(SQL Server)笔记 第四章 嵌套查询和其他查询子句
数据库原理与应用(SQL Server)笔记 第四章 嵌套查询和其他查询子句
数据库原理与应用(SQL Server)笔记 第四章 嵌套查询和其他查询子句
|
SQL 关系型数据库 MySQL
explain 使用简介|学习笔记
快速学习 explain 使用简介
127 0
explain 使用简介|学习笔记
|
SQL JSON 关系型数据库
JSON格式执行计划(6)—mysql执行计划(五十二)
JSON格式执行计划(6)—mysql执行计划(五十二)
|
SQL 关系型数据库 MySQL
子查询注意事项&semi-join(2)—mysql基于规则优化(四十五)
子查询注意事项&semi-join(2)—mysql基于规则优化(四十五)
SQL入门第三篇——连接查询
什么是连接查询 • 从一张表跨越到另一张表进行查询,叫做跨表查询,多张表联合起来查询数据,称为连接查询 • 连接查询的分类:SQL92:1992年出现的语法SQL99:1999年出现的语法;我们学习这个 • 那么表之间的连接方式又有哪些呢? • 内链接:等值连接,非等值连接,自连接 • 外连接:左外连接(左连接)右外连接(右连接)