Cypher索引、约束、统计
1.索引
1.1创建索引
使用CREATE INDEX ON可以在拥有某个标签的所有节点的某个属性上创建索引。注意,索引是在后台创建,并不能立刻就生效。
CREATE INDEX ON :Person(name) |
本例在拥有Person标签的所有节点的name属性上创建了索引。
1.2 删除索引
使用DROP INDEX可以删除拥有某个标签的所有节点的某个属性上的索引。
DROP INDEX ON :Person(name) |
1.3 使用索引
通常不需要在查询中指出使用哪个索引,Cypher自己会决定。例
MATCH (person:Person { name: 'Andres' }) RETURN person |
1.4 在WHERE等式中使用索引
在WHERE语句中的对索引的属性进行相等比较时,索引将自动被使用。
MATCH (person:Person) WHERE person.name = 'Andres' RETURN person |
1.5 使用WHERE不等式中使用索引
在WHERE语句中的对索引的属性进行不等(范围)比较时,索引将自动被使用。
MATCH (person:Person) WHERE person.name > 'B' RETURN person |
1.6 在 IN中使用索引
下面查询中针对 person.name的IN断言将使用Person(name)索引。
MATCH (person:Person) WHERE person.name IN ['Andres', 'Mark'] RETURN person |
1.7 在STARTS WITH中使用索引
下面的查询语句在针对person.name的STARTS WITH断言将使用Person(name)索引。
MATCH (person:Person) WHERE person.name STARTS WITH 'And' RETURN person |
1.8 在检查属性存在性时使用索引
下面查询中的has(p.name)断言将使用Person(name)索引。
MATCH (p:Person) WHERE exists(p.name) RETURN p |
2.约束
Neo4j通过使用约束来保证数据完整性。约束可应用于节点或者关系。可以创建节点属性的唯一性约束,也可以创建节点和关系的属性存在性约束。
可以使用属性的存在性约束确保拥有特定标签的所有节点或者拥有特定类型的所有关系的属性是存在的。所有的试图创建新的没有该属性的节点或关系,以及试图删除强制属性的查询都将失败。注意:只有Neo4j企业版才具有属性存在性约束这个高级功能。
可以对某个给定的标签添加多个约束,也可以将唯一性约束和存在性约束同时添加到同一个属性上。
在属性上添加唯一性约束的时候,同时也会自动为该属性添加一个索引。
2.1节点属性的唯一性约束
2.1.1 使用IS UNIQUE语法创建约束
它能确保数据库中拥有特定标签和属性值的节点是唯一的。
CREATE CONSTRAINT ON (book:Book) ASSERT book.isbn IS UNIQUE |
2.1.2 删除唯一性约束
使用DROP CONSTRAINT可以删除数据库中的一个约束。
DROP CONSTRAINT ON (book:Book) ASSERT book.isbn IS UNIQUE |
2.1.3 创建遵从属性唯一性约束的节点
创建一个数据库中还不存在的isbn的Book节点。
CREATE (book:Book { isbn: '1449356265', title: 'Graph Databases' }) |
2.1.4 创建违背属性唯一性约束的节点
创建一个数据库中已经存在的isbn的节点。
CREATE (book:Book { isbn: '1449356265', title: 'Graph Databases' }) |
这种情况下,节点将创建失败。
错误消息
Node 0 already exists with label Book and property "isbn"=[1449356265]
2.1.5 因为冲突的节点而创建属性唯一性约束失败
当数据库中已经有两个Book节点拥有相同的isbn号时,在Book节点的isbn属性上创建属性唯一性约束。
CREATE CONSTRAINT ON (book:Book) ASSERT book.isbn IS UNIQUE |
这种情况下约束将创建失败,因为它与已有的数据冲突。可以选择创建索引或者移除冲突的节点然后再重新创建约束。
错误消息
Unable to create CONSTRAINT ON ( book:Book ) ASSERT book.isbn IS UNIQUE:
Multiple nodes with label `Book` have property `isbn` = '1449356265':
node(0)
node(1)
2.2节点属性存在性约束
2.2.1 使用ASSERT exists(variable.propertyName)创建约束,
可确保有指定标签的所有节点都有一个特定的属性。
CREATE CONSTRAINT ON (book:Book) ASSERT exists(book.isbn) |
2.2.2 删除节点属性存在性约束
使用DROP CONSTRAINT可以从数据库中移除一个约束。
DROP CONSTRAINT ON (book:Book) ASSERT exists(book.isbn) |
2.2.3 创建遵从属性存在性约束的节点
创建一个存在isbn属性的Book节点。
CREATE (book:Book { isbn: '1449356265', title: 'Graph Databases' }) |
2.2.4 创建违背属性存在性约束的节点
在:Book(isbn)有存在性约束的情况下,试图创建一个没有isbn属性的Book节点。
CREATE (book:Book { title: 'Graph Databases' }) |
错误消息
Node 1 with label "Book" must have the property "isbn" due to a constraint
2.2.5 删除有存在性约束的节点属性
在:Book(isbn)有存在性约束的情况下,试图从一个已存在的Book节点移除isbn属性。
MATCH (book:Book { title: 'Graph Databases' }) REMOVE book.isbn |
这种情况下,移除属性将失败。
错误消息
Node 0 with label "Book" must have the property "isbn" due to a constraint
2.3关系属性存在性约束
2.3.1使用ASSERT exists(variable.propertyName)创建约束,可确保特定类型的所有关系都有一个特定的属性。
REATE CONSTRAINT ON ()-[like:LIKED]-() ASSERT exists(like.day) |
2.3.2删除关系属性存在性约束
使用DROP CONSTRAINT从数据库中移除一个约束。
DROP CONSTRAINT ON ()-[like:LIKED]-() ASSERT exists(like.day) |
2.3.3创建遵从属性存在性约束的关系
创建一个存在day属性的LIKED关系。
MATCH (TomH:Person {name:'Tom Hanks', born:1956}), (book:Book { isbn: '1449356265', title: 'Graph Databases' }) CREATE (TomH)-[like:LIKED { day: 'yesterday' }]->(book) return TomH,book |
2.3.4创建违背属性存在性约束的关系
在有:LIKED(day)存在性约束的情况下,试图创建一个没有day属性的LIKED关系。
MATCH (Nora :Person {name:'Nora Ephron'}), (book:Book { isbn: '1449356265', title: 'Graph Databases' }) CREATE (Nora)-[like:LIKED]->(book) return Nora,book
|
这种情况下,关系将创建失败。
错误消息
Relationship 1 with type "LIKED" must have the property "day" due to a constraint
2.3.5移除具有存在性约束的关系属性
有:LIKED(day)存在性约束的情况下,试图从一个已有LIKED关系中移除day属性。
MATCH (TomH :Person {name:'Tom Hanks'})-[like:LIKED]-> (book:Book { isbn: '1449356265', title: 'Graph Databases' }) REMOVE like.day |
错误消息
Relationship 0 with type "LIKED" must have the property "day" due to a constraint
3.统计
当执行一个Cypher查询时,它将先编译为一个执行计划(execution plan),该计划可以运行并响应查询。为了给查询提供一个高效的计划,Neo4j需要数据库的信息,如schema有什么索引和约束存在?Neo4j也使用统计信息来保持数据库优化执行计划。有了这些信息,Neo4j就能决定采用哪种模式将获得最好的执行计划。
Neo4j通过对数据采样来获得如下统计信息:
- 拥有特定标签的节点的数量
- 每个索引的可选择性
- 按类型分的关系的数量
- 以拥有指定标签的节点开始或者结束的关系,按类型分各自的数量
Neo4j以两种方式来保持这些统计信息的更新。以标签数量为例,每当设置或者删除一个节点的标签的时候,这些数量都会被更新。Neo4j需要扫描所有索引以获得可选择的数量。
3.1配置选项
当上述统计信息发生变化时,缓存的执行计划将被重新生成。下面的配置项可以控制执行计划的更新。
dbms.index_sampling.background_enabled
控制当需要更新时索引是否会自动重新采样。
dbms.index_sampling.update_percentage
控制多大比例的索引被更新后才触发新的采样
cypher.statistics_divergence_threshold
多少统计信息发生变化后当前的执行计划就被认为过时了(需要重新生成执行计划)。参数值0.0意味着有变化就更新,1.0意味着永远都不更新。
3.2手动索引采样
重新采样可使用内嵌的db.resampleIndex()和db.resampleOutdatedIndexes()两个内嵌过程来触发。
下面是触发重采样的例子:
CALL db.resampleIndex(":Person(name)");
CALL db.resampleOutdatedIndexes();