sergiogarciasilva opened a new issue, #2575:
URL: https://github.com/apache/age/issues/2575
**Environment:** Apache AGE 1.7.0, PostgreSQL 17. Graph with ~45,700
vertices (label
`:Function` among others) and ~139,000 `:CALLS` edges, on the order of a few
dozen distinct
vertex labels total. Standard btree expression indexes present on the
per-label child tables.
### Symptom
An unlabelled `MATCH (n)` is dramatically more expensive to *plan* than the
same pattern with
a label, even when both return comparable row counts and neither touches
many rows at
execution time:
```
MATCH (n) RETURN n LIMIT 1
```
Planning Time: **133.367 ms**
```
MATCH (n:Function) RETURN n LIMIT 1
```
Planning Time: **0.312 ms**
That's **427x**, and it's entirely in planning, not execution — the
execution time for both
is negligible by comparison. This is easy to miss in practice because Cypher
hides the
relational model underneath, so nothing about the query looks like it should
be
label-count-sensitive.
### Mechanism
Read in source (`src/backend/parser/cypher_clause.c:7125-7141`, AGE 1.7.0):
when a `MATCH`
pattern has no label, the generated RTE points at the parent table
(`_ag_label_vertex` for
nodes, the equivalent for edges) with inheritance active (`inh = true`).
Every vertex label is
implemented as a PostgreSQL child table of that parent
(`<graph>."<Label>"`), so with
inheritance active the planner has to expand and cost every child table —
and every index on
every child table — during planning. With a label given, the RTE points
directly at that one
child table, no expansion needed.
This is not an AGE executor bug — it's standard PostgreSQL
inheritance-planning behavior,
working as designed. The gap is that nothing surfaces this cost to a Cypher
user before they
hit it: an unlabelled `MATCH (n)` reads as a small, generic query, but its
planning cost scales
with the *total* number of labels defined in the graph, independent of how
selective the
pattern is or how many rows match.
### Minimal reproduction (anyone can run this)
```sql
SELECT create_graph('label_scale_bench');
-- create N distinct vertex labels and insert a handful of vertices into each
DO $$
BEGIN
FOR i IN 1..50 LOOP
PERFORM create_vlabel('label_scale_bench', format('L%s', i));
EXECUTE format(
$q$SELECT * FROM cypher('label_scale_bench', $c$ CREATE (:L%s {v: 1})
$c$) AS (v agtype)$q$,
i
);
END LOOP;
END $$;
-- compare planning time, unlabelled vs labelled
EXPLAIN (ANALYZE, BUFFERS)
SELECT * FROM cypher('label_scale_bench', $$ MATCH (n) RETURN n LIMIT 1 $$)
AS (n agtype);
EXPLAIN (ANALYZE, BUFFERS)
SELECT * FROM cypher('label_scale_bench', $$ MATCH (n:L1) RETURN n LIMIT 1
$$) AS (n agtype);
```
Repeat with N = 10, 50, 100, 200 labels and chart Planning Time for the
unlabelled form against
N. We'd expect it to grow with the label count (at least linearly, likely
worse once per-child
index stats get pulled in); the labelled form should stay flat.
### Suggested fix (cheap end first)
This doesn't need an executor rewrite to be worth fixing:
1. Document it — a line in the manual's `MATCH` section noting that an
unlabelled `MATCH`
scans/plans over every vertex (or edge) label in the graph, and that this
cost grows with
the number of distinct labels, would let people opt into labelling on
purpose instead of
discovering it via a planning-time cliff.
2. Consider a `NOTICE`/`HINT` when planning an unlabelled `MATCH` against a
graph with more
than some threshold of labels, pointing at the label-count cost.
3. Longer term, this is presumably related to how much PostgreSQL's own
inheritance-planning
cost can be reduced (partition pruning heuristics,
`constraint_exclusion`, etc.) — but that's
a much bigger scope than this issue is asking for.
Happy to run the N-label benchmark script above and post the growth curve if
that'd help
prioritize this.
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: [email protected]
For queries about this service, please contact Infrastructure at:
[email protected]