Hi Tatsuya,

I reviewed v1 of this patch on PostgreSQL 20devel on macOS ARM64.

The patch applied cleanly and built successfully. I also ran the full
regression suite using an out-of-tree build configured with --enable-cassert
--enable-debug; all 243 tests passed in my environment.

I tested the Function Scan storage reporting under several scenarios,
including memory-backed and disk-backed tuplestores by varying work_mem, ROWS
FROM with multiple functions, zero-row execution, WITH ORDINALITY, plans
containing both Sort and Function Scan, and user-defined set-returning
functions.

As a basic disk-backed case, with work_mem = '64kB':

EXPLAIN (ANALYZE)SELECT * FROM generate_series(1,10000);

reported:

Storage: Disk  Maximum Storage: 137kB
Buffers: temp read=18 written=18

I also tested a SQL-language SRF whose underlying query performs an
internal ORDER BY. With work_mem = '64kB', the Function Scan reported:

Storage: Disk  Maximum Storage: 1758kB
Buffers: shared hit=19, temp read=843 written=879

With the same function and work_mem = '16MB', it reported:

Storage: Memory  Maximum Storage: 4150kB

with no temporary-buffer activity reported by the outer EXPLAIN.

The Storage / Maximum Storage reporting behaved consistently across the
cases I tested. I did not find a correctness issue with v1.

Regards,
Shashishekar Hullahally Anantharamu

On Thu, Sep 3, 2026 at 10:21 PM Tatsuya Kawata <[email protected]>
wrote:

> Hi,
>
> 1eff8279d4, 95d6e9af07 and 40708acd65 added memory/disk usage for
> Materialize, WindowAgg, CTE Scan, Table Function Scan and Recursive
> Union in EXPLAIN ANALYZE. [1]
> So I wanted to add memory/disk usage for Function Scan.
>
>
> ## The patch
>
> It follows the shape of the existing five nodes, so there are only two
> things worth mentioning.
>
> 1. Handling of multiple tuplestores
>
>    A FunctionScan uses one tuplestore per function, so there can be more
>    than one when ROWS FROM is used.  I used the same rule as Recursive
>    Union: the storage type of whichever one consumed the most
>    memory/disk, and the sum of the sizes of them all.
>
> 2. Moving FunctionScanPerFuncState to execnodes.h
>
>    Its definition lives in nodeFunctionscan.c and execnodes.h only has a
>    forward declaration, so explain.c cannot reach funcstates[i].tstore.
>    The state structs of the other five nodes are all in execnodes.h, so
>    I moved this one there too.
>
>
> ## Behavior
>
> Measured with work_mem = 64kB.  On its own, 1000 rows gives
> "Memory  56kB" and 500000 rows gives "Disk  6836kB".
>
>   -- two identical functions: exactly twice the single-function figure
>   SELECT count(*) FROM ROWS FROM (generate_series(1,500000),
>                                   generate_series(1,500000)) g;
>     Storage: Disk  Maximum Storage: 13672kB
>
>   -- a small one and a large one: type from the larger, size is the sum
>   SELECT count(*) FROM ROWS FROM (generate_series(1,10),
>                                   generate_series(1,500000)) g;
>     Storage: Disk  Maximum Storage: 6853kB
>
>
> ## What is reported when loops > 1
>
> The Storage line follows the same policy as the Sort Method line of
> Sort, that is, it reports the peak recorded by whichever object is still
> around at EXPLAIN time.  The statistics live inside the Tuplestorestate
> (or Tuplesortstate) and are lost along with it when rescan calls end().
> ExecReScanFunctionScan() has the same shape as
> ExecReScanTableFuncScan(), and on master both Sort and Table Function
> Scan already change what they report if you reorder the rows.
> When loops is 1 the value is of course exact.
>
> I could not find a settled policy for how this kind of per-node resource
> statistic should be aggregated when loops > 1.  So this patch follows
> Sort.  If the consensus is that the maximum across all loops should be
> reported instead, that would be a separate change spanning Sort,
> Incremental Sort, Material, Table Function Scan and Function Scan, and
> I would be happy to work on it separately.
>
>
> make check passes all 245 tests.
> Patch attached.
>
> Regards,
> Tatsuya Kawata
>
> [1] Discussion for 40708acd65:
> https://postgr.es/m/20240918.211246.1127161704188186085.ishii%40postgresql.org
>
>

Reply via email to