在neo4j中有两个内存配置项,直接决定了neo4j的性能。在neo4j中最重要的内存的配置有两项:
堆内存是neo4j运行时需要的内存,用于:
堆的大小决定于neo4j的使用性质。配置堆内存的参数如下:
dbms.memory.heap.initial_size=16384m
dbms.memory.heap.max_size=16384m
说明:官方建议堆内存不要过大,过大容易产生full gc,导致程序停顿。在总物理内存足够的情况下(>56G),官方的建议值是:16G。
dbms.memory.pagecache.size=80g
在neo4j中,"页面缓存”用来缓存索引和数据。通过该参数的设置,可以把数据都加载到内存中。该参数的大小需要根据数据量和索引量,以及物理内存的大小来设置。
CREATE INDEX ON :Person(firstname)
CREATE INDEX ON :Person(age, country)
注意:只有复合索引的两个字段都被查询,复合索引才被使用,否则不会被使用。
CALL db.indexes
注意:当看到state这一栏的状态为"ONLINE"时,索引才生效。
尽可能的建立更多种类的关系标签, 而不是给关系加属性, 这样会很低效, 即使给关系加上手工索引。
生产环境用neo4j-import加载数据很快,但得先构造很多个csv文件,另外该命令只用于neo4j初始化状态。
增量数据的同步加载又不想暂停数据库服务,需要使用:load csv 或者apoc
适合做图存储和基于模式匹配的子图查询,并不适合做大量与搜索无关的数据存储工作,比如:元数据查询就不应该放到图数据库中。
$ echo 'deadline' > /sys/block/sda/queue/scheduler
$ cat /sys/block/sda/queue/scheduler
noop [deadline] cfq
使用G1垃圾回收器,neo4j-3.5的默认启动参数应该是G1。也可以通过jsp -lv查看一下。
-XX:+UseG1GC
为客户端(client)建立的每个连接都分配给连接器的线程池。空闲连接不会消耗服务器端的任何资源,并且会针对来自客户端的消息对其进行监视。到达连接的每条消息都会触发线程池中可用线程上的连接调度。
Bolt线程池具有最小和最大容量。 它从可用的最小线程数开始,并根据工作负载增长到最大数量。 闲置超过指定时间段的线程将停止并从池中删除,以释放资源。 但是,池的大小永远不会低于最小值。
以下配置选项可用于配置Bolt连接器:
选项 | 默认值 | 描述 |
---|---|---|
dbms.connector.bolt.thread_pool_min_size | 5 | 即使空闲也将始终保持最小线程数。 |
dbms.connector.bolt.thread_pool_max_size | 400 | 线程池将创建的最大线程数。 |
dbms.connector.bolt.thread_pool_keep_alive | 5m | 线程池在从池中终止空闲线程之前将等待的持续时间。但是,线程数永远不会低于dbms.connector.bolt.thread_pool_min_size。 |
说明:在并发不大的情况下该参数可以不用设置。
才启动时需要对neo4j的数据进行预热,通过以下命令进行预热:
MATCH (n) OPTIONAL MATCH (n)-[r]->() RETURN count(n.name) + count(r)
注意:若数据量很大,预热的时间可能会比较长。我这里100G内存,16Gheapsize+80gpagecache,32CPU,使用了56分钟才预热完成。
可以根据内存大小,调整预热的条件,可以把数据预热到内存。
可以通过explain(不会执行语句)语句来查看执行计划,比如:是否使用索引等。
explain match data=(na)-[r]->(nb:company{name:'ss'}) return data
在这里查看数据查询执行计划输出的解释。
注意:还有一个命令可以查看执行计划,但profile命令会执行语句,explain是不会执行查询语句。
关注指标:
说明:两个值都是越小越好。
MATCH (a:Author)-[:author_is_in_field]->(f:Field)
WHERE f.field_level = "L3"
RETURN a.auhtor_name,f.field_name,f.field_reference_count
LIMIT 10
MATCH (a:Author)-[:author_is_in_field]->(f:Field{field_level:"L3"})
RETURN a.auhtor_name,f.field_name,f.field_reference_count
LIMIT 10
MATCH (b:BANK {bank_id : 'bank536039'}),(c:COMP {comp_id : 'comp323275' }) return count(b),count(c);
这种写法查询性能会很快,毫秒级返回。
没有指定类型(标签)的查询是非常耗时和耗性能的。所以,在查询时都必须要指定类型。而且,尽可能在一类标签(相当于一张表)中进行查询。
比如,下面的语句就会很慢:
MATCH (n) OPTIONAL MATCH (n)-[r]->() RETURN count(r)
若加上类型(标签)就会快很多,比如:
MATCH (n: USER) OPTIONAL MATCH (n)-[r:IP]->() RETURN count(n.name) + count(r)
当要查询多个类型的点或边时,最好将一个复合的match子句拆分成多个match子句。例如:
MATCH (b:BANK),(c:COMP) return count(distinct(b)),count(distinct(c))
说明:在1亿个点7.9亿条边的情况下,这条语句非常耗时。explain后发现,该语句会先产生一个非常大的集合,然后在该集合中把b,c两个类型的点分别出来再计算数量。
MATCH (b:BANK)
with count(b) as banks
MATCH (c:COMP)
return count(c) as comps,banks
说明:该语句会在<5秒返回结果。
增加WHERE语句、配合使用AND、OR等加大查询复杂度。