Skip to content

perf(catalog): reuse resolved graph id in ensure_current_graph - #19

Open
ysys143 wants to merge 1 commit into
Evokoa:mainfrom
ysys143:perf/avoid-duplicate-graph-resolution
Open

perf(catalog): reuse resolved graph id in ensure_current_graph#19
ysys143 wants to merge 1 commit into
Evokoa:mainfrom
ysys143:perf/avoid-duplicate-graph-resolution

Conversation

@ysys143

@ysys143 ysys143 commented Aug 5, 2026

Copy link
Copy Markdown

Fixes #18.

ensure_current_graph() resolves the selected graph, then calls current_catalog_state()read_catalog(), which resolves the same graph again via selected_or_default_graph_id_via_definer(). This adds current_catalog_state_for_graph(graph_id) so the already-resolved id is reused.

No behavior change: read_catalog() delegates to read_catalog_for_graph() once it has resolved the id, so the executed catalog reads are identical minus the duplicate resolution.

Measurement

PostgreSQL 17.10, 1,308,553 nodes / 3,599,812 edges, pinned seed set shared by both builds, warmup applied, median of 40 runs, single connection.

metric 1.0.0 this PR delta
minimal-work expand() (fixed cost) 5.179 ms 4.070 ms -21.4%
expand() 1 hop, LIMIT 50 6.148 ms 4.923 ms -19.9%
expand() 1 hop reverse, LIMIT 50 4.980 ms 4.217 ms -15.3%
expand() 2 hop, LIMIT 50 7.242 ms 7.033 ms -2.9%
graph.status() (negative control) 3.495 ms 3.683 ms +5.4%

Row counts identical in every case (160 / 141 / 1,183). graph.status() exercises a path this PR does not touch and puts run-to-run noise at ±5%, so the fixed-cost reduction is above noise. The 2-hop case is traversal-dominated, hence the small share.

Tests

Schema-drift behavior is what the removed duplicate feeds, and it stays covered by the existing pg_tests catalog_drift_requires_rebuild and schema_drift_detects_live_ddl_changes. No new public SQL behavior is introduced, so no new SQL test is added.

cargo fmt --check and cargo check --features pg17 pass.

Note

I was not able to run cargo pgrx test pg17 in my container — the test harness fails at link time with undefined references to PG_exception_stack / ErrorContext, which looks like a local toolchain issue rather than something in this change. I would appreciate CI confirming the suite.

ensure_current_graph() resolves the selected graph, then calls
current_catalog_state() -> read_catalog(), which resolves the same graph
again through selected_or_default_graph_id_via_definer(). Every traversal
call therefore pays for two definer SPI lookups of the same row.

Add current_catalog_state_for_graph(graph_id) so the already-resolved id
is reused. No behavior change: read_catalog_for_graph() is the same code
path read_catalog() delegates to once it has resolved the id.

Measured on PG 17.10, 1,308,553 nodes / 3,599,812 edges, pinned seed set,
warmup applied, median of 40 runs:

  minimal-work expand()   5.179 ms -> 4.070 ms  (-21.4%)
  expand() LIMIT 50 (Q2)  6.148 ms -> 4.923 ms  (-19.9%)
  expand() LIMIT 50 (Q3)  4.980 ms -> 4.217 ms  (-15.3%)
  graph.status() control  3.495 ms -> 3.683 ms  (+5.4%)

Row counts identical in all cases. graph.status() is a negative control on
a path this change does not touch, putting run-to-run noise at +/-5%.

Schema-drift behavior stays covered by the existing pg_tests
catalog_drift_requires_rebuild and schema_drift_detects_live_ddl_changes.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Duplicate graph resolution on every traversal call (~21% of the per-call fixed cost)

1 participant