Re: [SQL/PGQ] Native executor for Graph query

From: Henson Choi <assam258(at)gmail(dot)com>
To: Henri GASC <henri(dot)gasc(at)airbus(dot)com>
Cc: pgsql-hackers(at)lists(dot)postgresql(dot)org
Subject: Re: [SQL/PGQ] Native executor for Graph query
Date: 2026-09-17 11:21:43
Message-ID: CAAAe_zByDpnT0L1iG_dnneSFjxhq6u9p62Eqmo8uE_1p_jjn4g@mail.gmail.com
Views: Whole Thread | Raw Message | Download mbox | Resend email
Thread:
Lists: pgsql-hackers

Hi Henri,

The patch I sent earlier linked the copies at their roots only. Attached
is that fixed: wip-graphscan-planstate-updown-rev-002.txt replaces it and
applies on top of v2-0008 as before.

graph_push() now pairs a new copy with the previous one node by node.
Both trees are ExecInitNode() of copyObject() of the same Plan, so
planstate_tree_walker() visits them in the same order; collecting one in
that order and walking the other pairs them up. A node's down is then
the node in the same position in the next depth's copy, and the root's
chain is, as the special case of that, the per-depth copies in order --
which is what GraphScan follows when it descends and backtracks.

The rollup in ExecShutdownPlanStateChain() is now one pass over the tree
with each node folding its own chain. Shutdown stays on the root's chain
as before, since it is per copy: ExecShutdownNode() recurses into each
copy's tree by itself, so calling it per node would tear each one down
twice.

The expected output changes like this:

-> Append (actual rows=0.90 loops=10)
Buffers: shared hit=51
-> Seq Scan on e1_2 (actual rows=0.50 loops=10)
Buffers: shared hit=10
-> Bitmap Heap Scan on e1_3 (actual rows=0.20 loops=10)
Buffers: shared hit=11
...

Before, the Append read loops=10 over eight nodes that all read loops=3,
and its Buffers read 51 against 16 summed over its children. The
children now sum to 51. It also brought out something that was not
visible at all: the e2_1 scan reported no rows before, when it was in
fact finding two -- they were found below depth 0 and so never reported.

Two things are still open.

First, part of the rollup has to be done per node type. InstrAggNode()
covers PlanState.instrument, but an index scan's Index Searches does not
live there; it comes from IndexScanInstrumentation (iss_Instrument,
ioss_Instrument, biss_Instrument). So that one counter keeps depth 0's
value, and in the output above it reads Index Searches: 3 under
loops=10. It agreed with loops=3 before this change, so this is an
inconsistency the change introduces. show_indexscan_info() in explain.c
already sums the parallel workers' copies of that counter in exactly
that spot, and the chain wants the same treatment in the same place.
IndexScan, IndexOnlyScan and BitmapIndexScan are the three affected, and
any other node type holding its own statistics is in the same position.
This patch does not do it.

Second, ExecShutdownPlanStateChain() adds the same numbers again if it
runs more than once. EXEC_FLAG_BACKWARD is only set for scrollable
cursors, so fetching a NO SCROLL cursor in batches has ExecutePlan() call
ExecShutdownNode() once per batch, and with instrumentation on
InstrAggNode() accumulates each time. Gather guards against re-entry in
ExecShutdownGather(), but simply running the rollup once here would drop
everything after the first batch. Folding a delta -- resetting the
member's accumulated counters once merged -- looks like the right shape,
except that Instrumentation's configuration fields must not be touched,
and I have not settled on how. I would welcome your thoughts.

It builds and the graph_table regression test passes.

Best regards,
Henson

Attachment Content-Type Size
wip-graphscan-planstate-updown-rev-002.txt text/plain 58.5 KB

In response to

Browse pgsql-hackers by date

  From Date Subject
Next Message Hayato Kuroda (Fujitsu) 2026-09-17 11:35:24 RE: pgoutput: schema cache cleanup after streamed 2PC
Previous Message alvherre@kurilemu.de 2026-09-17 11:16:04 Re: Bug in logical decoding with DDL and subtransactions