Property, range and composite indexes
Wiki / Indexes and constraints
On this page
Property indexes
A property index on (label, property) turns MATCH (n:Label {prop: v}) and
WHERE n.prop = v from an O(|nodes|) scan into an O(1)/O(log n) lookup.
CREATE INDEX ON :Person(email); // declare (backfills existing data)
SHOW INDEXES; // property, composite and element indexes
The planner uses an index automatically when a pattern/predicate allows it.
Confirm with EXPLAIN:
EXPLAIN MATCH (p:Person {email: $e}) RETURN p;
// Match: NodeIndexSeek(:Person .email) <- index is used
Notes:
- Creating an index backfills existing matching nodes — every node that carries the label at that moment, under each of its labels — and every later write keeps it current. Only nodes are indexed: there are no relationship property indexes, and an unlabelled node is never indexed. Re-declaring an existing index is accepted but re-scans the label.
- A built-in label/token index is always on (not declared), making
MATCH (n:Label)cost O(label population) rather than O(all nodes); the planner anchors a multi-label pattern on its rarest label. - The plain
CREATE INDEXindex is hash/equality only. For range queries, declare a range index (Property, range and composite indexes). Composite non-unique indexes are supported (see below); composite uniqueness uses node keys, Constraints and shared uniqueness.
Range (ordered) indexes
A range index is ordered, so it accelerates </<=/>/>= predicates (and
equality) — the planner uses it when a clause WHERE ranges over the indexed
property.
CREATE RANGE INDEX FOR (p:Person) ON (p.age); // 5.x form (a name may precede FOR)
SHOW INDEXES; // the `type` column shows RANGE vs BTREE
EXPLAIN MATCH (p:Person) WHERE p.age >= 18 AND p.age < 65 RETURN p;
// Match: NodeIndexSeekByRange(:Person .age) <- range index is used
STARTS WITH is a range in disguise, and plans the same seek:
the prefix desugars to >= prefix AND < successor(prefix) internally, for a
literal or a parameter prefix alike.
CREATE RANGE INDEX FOR (p:Person) ON (p.name);
EXPLAIN MATCH (p:Person) WHERE p.name STARTS WITH 'Al' RETURN p;
// Match: NodeIndexSeekByRange(:Person .name) <- prefix seek
Composite (multi-property) indexes
Both kinds take a property list, giving a composite index over several properties of a label:
CREATE INDEX FOR (p:Person) ON (p.first, p.last); // composite hash
CREATE RANGE INDEX FOR (e:Event) ON (e.category, e.day); // composite range
-
A composite index covers a node only when it carries the label and every indexed property — a node missing one is simply not indexed.
-
The planner uses a composite hash index when every property is bound by equality (
WHERE p.first = $f AND p.last = $l, or the inline form(:Person {first: $f, last: $l})), and prefers it over a single-property index when it binds more properties:EXPLAIN MATCH (p:Person) WHERE p.first = 'Ada' AND p.last = 'Lovelace' RETURN p; // Match: NodeIndexSeek(:Person (first, last)) -
A composite range index serves a leading-prefix equality plus an optional range on the next property (
WHERE e.category = 'a' AND e.day >= 5). -
SHOW INDEXESlists a composite index with its properties joined in thepropertycolumn. Composite uniqueness is provided separately by node-key constraints (Constraints and shared uniqueness.
Removing indexes
After the examples, remove indexes with DROP INDEX ON :Person(email),
DROP RANGE INDEX FOR (p:Person) ON (p.age) or
DROP INDEX FOR (p:Person) ON (p.first, p.last). A constraint-backed index
cannot be dropped while its constraint exists.
Related articles
EXPLAIN and PROFILE · Resident and hybrid storage · Schema and maintenance procedures