Hacktoberfest 2026: le issue che i maintainer hanno segnato per ottobre, aperte e adatte ai principianti. Sfoglia le issue Hacktoberfest

MATCH (n) without a label pays PostgreSQL table-inheritance planning cost proportional to the total number of vertex labels in the graph

Aperta
#2,575 0 commenti 0 reazioni 0 assegnatari Vedi su GitHub

I maintainer di solito rispondono entro 1 giorno

Nessuno ha ancora preso questa issue.

Valutazione

Difficoltà
3/5
Tempo stimato
1-2 giorni
Idoneità per principianti
72/100
Tipo di issue
Bug
Chiarezza
Abbastanza chiara
Stato di attività
Attiva
Stack tecnologico
c, postgresql, sql
Ambito
databases

Direzione di ricerca

Start by reading src/backend/parser/cypher_clause.c:7125-7141 and run the supplied N-label SQL benchmark with EXPLAIN (ANALYZE, BUFFERS). Confirm how planning time changes for labelled and unlabelled MATCH queries, then inspect the manual's MATCH section. Done should clearly document the label-count planning cost, or provide the agreed warning if that scope is chosen.

Scritto dal modello di indicizzazione a partire dal testo della issue.

Descrizione

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)
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.

Lingua principale
C
Stelle
4.9k
Fork
529
Merge medio
8g 15h
PR unite (30g)
3

Preparare l'ambiente

Come iniziare

  1. Leggi tutta la issue e poi la guida ai contributi del progetto.
  2. Commenta sulla issue per dire che te ne occupi tu — evita che due persone facciano lo stesso lavoro.
  3. Fai un fork del repository e lavora su un branch.
  4. Apri una pull request che faccia riferimento al numero della issue.

Altre issue di apache/age

Tutte le issue di apache/age

Issue simili

Altre issue su C

Ricevi le nuove issue nella tua casella

Un breve riepilogo di issue GitHub adatte ai principianti.