3.5.1. Indexes

A database index is a redundant copy of information in the database for the purpose of making retrieving said data more efficient. This comes at the cost of additional storage space and slower writes, so deciding what to index and what not to index is an important and often non-trivial task.

Cypher allows the creation of indexes over a property for all nodes that have a given label. Once an index has been created, it will automatically be managed and kept up to date by the database whenever the graph is changed. Neo4j will automatically pick up and start using the index once it has been created and brought online.

3.5.1.1. Create an index

To create an index on a property for all nodes that have a label, use CREATE INDEX ON. Note that the index is not immediately available, but will be created in the background.

Query. 

CREATE INDEX ON :Person(name)

Result. 

+--------------------------------------------+
| No data returned, and nothing was changed. |
+--------------------------------------------+

3.5.1.2. Drop an index

To drop an index on all nodes that have a label and property combination, use the DROP INDEX clause.

Query. 

DROP INDEX ON :Person(name)

Result. 

+-------------------+
| No data returned. |
+-------------------+
Indexes removed: 1

3.5.1.3. Use index

There is usually no need to specify which indexes to use in a query, Cypher will figure that out by itself. For example the query below will use the Person(name) index, if it exists. If you want Cypher to use specific indexes, you can enforce it using hints. See Section 3.6.4, “USING”.

Query. 

MATCH (person:Person { name: 'Andres' })
RETURN person

Query Plan. 

+-----------------+----------------+------+---------+-----------+---------------+
| Operator        | Estimated Rows | Rows | DB Hits | Variables | Other         |
+-----------------+----------------+------+---------+-----------+---------------+
| +ProduceResults |              1 |    1 |       0 | person    | person        |
| |               +----------------+------+---------+-----------+---------------+
| +NodeIndexSeek  |              1 |    1 |       2 | person    | :Person(name) |
+-----------------+----------------+------+---------+-----------+---------------+

Total database accesses: 2

3.5.1.4. Use index with WHERE using equality

Indexes are also automatically used for equality comparisons of an indexed property in the WHERE clause. If you want Cypher to use specific indexes, you can enforce it using hints. See Section 3.6.4, “USING”.

Query. 

MATCH (person:Person)
WHERE person.name = 'Andres'
RETURN person

Query Plan. 

+-----------------+----------------+------+---------+-----------+---------------+
| Operator        | Estimated Rows | Rows | DB Hits | Variables | Other         |
+-----------------+----------------+------+---------+-----------+---------------+
| +ProduceResults |              1 |    1 |       0 | person    | person        |
| |               +----------------+------+---------+-----------+---------------+
| +NodeIndexSeek  |              1 |    1 |       2 | person    | :Person(name) |
+-----------------+----------------+------+---------+-----------+---------------+

Total database accesses: 2

3.5.1.5. Use index with WHERE using inequality

Indexes are also automatically used for inequality (range) comparisons of an indexed property in the WHERE clause. If you want Cypher to use specific indexes, you can enforce it using hints. See Section 3.6.4, “USING”.

Query. 

MATCH (person:Person)
WHERE person.name > 'B'
RETURN person

Query Plan. 

+-----------------------+----------------+------+---------+-----------+---------------------------------+
| Operator              | Estimated Rows | Rows | DB Hits | Variables | Other                           |
+-----------------------+----------------+------+---------+-----------+---------------------------------+
| +ProduceResults       |             10 |    1 |       0 | person    | person                          |
| |                     +----------------+------+---------+-----------+---------------------------------+
| +NodeIndexSeekByRange |             10 |    1 |       2 | person    | :Person(name) > {  AUTOSTRING0} |
+-----------------------+----------------+------+---------+-----------+---------------------------------+

Total database accesses: 2

3.5.1.6. Use index with IN

The IN predicate on person.name in the following query will use the Person(name) index, if it exists. If you want Cypher to use specific indexes, you can enforce it using hints. See Section 3.6.4, “USING”.

Query. 

MATCH (person:Person)
WHERE person.name IN ['Andres', 'Mark']
RETURN person

Query Plan. 

+-----------------+----------------+------+---------+-----------+---------------+
| Operator        | Estimated Rows | Rows | DB Hits | Variables | Other         |
+-----------------+----------------+------+---------+-----------+---------------+
| +ProduceResults |             24 |    2 |       0 | person    | person        |
| |               +----------------+------+---------+-----------+---------------+
| +NodeIndexSeek  |             24 |    2 |       4 | person    | :Person(name) |
+-----------------+----------------+------+---------+-----------+---------------+

Total database accesses: 4

3.5.1.7. Use index with STARTS WITH

The STARTS WITH predicate on person.name in the following query will use the Person(name) index, if it exists.

Query. 

MATCH (person:Person)
WHERE person.name STARTS WITH 'And'
RETURN person

Query Plan. 

+-----------------------+----------------+------+---------+-----------+-------------------------------------------+
| Operator              | Estimated Rows | Rows | DB Hits | Variables | Other                                     |
+-----------------------+----------------+------+---------+-----------+-------------------------------------------+
| +ProduceResults       |             26 |    1 |       0 | person    | person                                    |
| |                     +----------------+------+---------+-----------+-------------------------------------------+
| +NodeIndexSeekByRange |             26 |    1 |       2 | person    | :Person(name STARTS WITH {  AUTOSTRING0}) |
+-----------------------+----------------+------+---------+-----------+-------------------------------------------+

Total database accesses: 2

3.5.1.8. Use index when checking for the existence of a property

The has(p.name) predicate in the following query will use the Person(name) index, if it exists.

Query. 

MATCH (p:Person)
WHERE exists(p.name)
RETURN p

Query Plan. 

+-----------------+----------------+------+---------+-----------+---------------+
| Operator        | Estimated Rows | Rows | DB Hits | Variables | Other         |
+-----------------+----------------+------+---------+-----------+---------------+
| +ProduceResults |              2 |    2 |       0 | p         | p             |
| |               +----------------+------+---------+-----------+---------------+
| +NodeIndexScan  |              2 |    2 |       3 | p         | :Person(name) |
+-----------------+----------------+------+---------+-----------+---------------+

Total database accesses: 3