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();