Graph data is stored internally as multiple tables. Graph data searches are implemented as SELECT statements on those tables. The access plan can be checked with the EXPLAIN statement in the same way as for normal SQL statements.
Graph data consists of a table with a record for each node and a table with a record for each edge, and queries corresponding to graph data are implemented by joining and filtering those tables. Therefore, the approach to performance issues in graph searches is the same as for SELECT statements that include joins.
Example) Checking the access plan of a graph search
SELECT * FROM cypher('new_graph', $$ EXPLAIN (COSTS off) MATCH (:Person {name: 'Daedalus'})-[:FATHER_OF]->(person) WITH person.name AS name ORDER BY person.name RETURN name $$) AS (v agtype); QUERY PLAN ------------------------------------------------------------------------------------------------------------------------------------------------------------------ Sort Sort Key: (agtype_access_operator(VARIADIC ARRAY[_agtype_build_vertex(person.id, _label_name('25995'::oid, person.id), person.properties), '"name"'::agtype])) -> Hash Join Hash Cond: (person.id = _age_default_alias_1.end_id) -> Append -> Seq Scan on _ag_label_vertex person_1 -> Seq Scan on "Person" person_2 -> Hash -> Hash Join Hash Cond: (_age_default_alias_1.start_id = _age_default_alias_0.id) -> Seq Scan on "FATHER_OF" _age_default_alias_1 -> Hash -> Seq Scan on "Person" _age_default_alias_0 Filter: (properties @> '{"name": "Daedalus"}'::agtype) (14 rows)