Hacktoberfest 2026:メンテナが10月に向けて印を付けた、オープンで初心者向けの issue。 Hacktoberfest の issue を見る

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

オープン
#2,575 コメント 0 件 リアクション 0 件 担当者 0 名 GitHub で見る

メンテナーはふだん 1 日以内に返信

まだ誰も着手していません。

評価

難易度
3/5
見積もり時間
1〜2日
初心者へのやさしさ
72/100
issue の種類
バグ
明瞭さ
おおむね明確
活発さ
活発
技術スタック
c, postgresql, sql
領域
databases

調査の方向性

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.

索引モデルが issue の本文から書いたものです。

説明

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.

主要言語
C
スター
4.9k
フォーク
529
平均マージ
8日 15時間
マージ済み PR(30日)
3

環境構築

はじめの一歩

  1. issue を最後まで読み、次にプロジェクトのコントリビューションガイドを読みます。
  2. 着手することを issue にコメントします — 二人が同じ作業をするのを防げます。
  3. リポジトリをフォークし、ブランチを切って変更します。
  4. issue 番号を参照したプルリクエストを送ります。

apache/age のほかの issue

apache/age の issue をすべて見る

似ている issue

C の issue をもっと見る

新しい issue をメールで受け取る

初心者向けの GitHub issue を短くまとめたダイジェスト。