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]

Reply via email to