| From: | Chao Li <li(dot)evan(dot)chao(at)gmail(dot)com> |
|---|---|
| To: | David Rowley <dgrowleyml(at)gmail(dot)com> |
| Cc: | PostgreSQL Developers <pgsql-hackers(at)lists(dot)postgresql(dot)org> |
| Subject: | Re: Reduce memory overheads for storing a Memoize tuple |
| Date: | 2026-08-03 04:52:01 |
| Message-ID: | 0BD5FF1C-EE3E-44F1-B48C-51EAD8496890@gmail.com |
| Views: | Whole Thread | Raw Message | Download mbox | Resend email |
| Thread: | |
| Lists: | pgsql-hackers |
> On Aug 1, 2026, at 16:35, David Rowley <dgrowleyml(at)gmail(dot)com> wrote:
>
> a0942f441 added ExecCopySlotMinimalTupleExtra(), which accepts a
> parameter to specify the number of "extra" bytes that we want to
> allocate along with the MinimalTuple. That's now used in
> execGrouping.c to save some memory.
>
> The same optimisation can be applied in nodeMemoize.c. MemoizeTuple
> has a field for the tuple being stored and 1 other field to point to
> the next tuple cached for this MemoizeEntry. Here we could use
> ExecCopySlotMinimalTupleExtra() to specify that we want a pointer's
> worth of extra bytes palloc'd for the MinimalTuple, and then store the
> pointer to the next tuple in those bytes. This saves 16 bytes per
> cached tuple. 24 bytes less because we don't palloc a MemoizeTuple
> (including the MemoryChunk's 8 bytes), and 8 bytes more for the
> ExecCopySlotMinimalTupleExtra bytes, a net saving of 16 bytes per
> tuple.
>
> Making Memoize use less memory is useful in cases where the cache
> would otherwise have to reload entries that were cached previously but
> were evicted due to reaching memory limits.
>
> A quick example:
>
> create table t1 (a int not null);
> create table t2 (a int not null);
> insert into t1 select x from generate_series(1,100000) x,
> generate_series(1,100);
> create index on t1 (a);
> insert into t2 select x%1000+1 from generate_series(1,1000000)x;
> analyze t1,t2;
>
> explain analyze select count(*) from t1 inner join t2 on t1.a=t2.a;
>
> Master: Memory Usage: 3583kB
> Patched: Memory Usage: 2801kB
>
> Really, the savings are double what's reported by EXPLAIN ANALYZE, as
> CACHE_TUPLE_BYTES doesn't account for any of the MemoryChunks that are
> consumed by palloc. We're now doing 1 fewer palloc per tuple due to
> the removal of the palloc_object(MemoizeTuple) code, so more like 30%
> less memory for this case.
>
> Patch attached.
>
> David
> <v1-0001-Reduce-memory-overheads-for-storing-a-Memoize-tup.patch>
The optimized data structure looks good to me. The test result on my side exactly matches yours: 3583kB vs. 2801kB. I had to turn off hash join, otherwise the planner always chose a parallel hash join.
I have only one nitpick. MAXALIGN(sizeof(MinimalTuple)) appears 4 times. Would it make sense to define a macro for it, say MEMOIZE_TUPLE_LINK_SIZE?
Best regards,
--
Chao Li (Evan)
HighGo Software Co., Ltd.
https://www.highgo.com/
| From | Date | Subject | |
|---|---|---|---|
| Next Message | Ayush Tiwari | 2026-08-03 05:10:49 | Re: Avoid unnecessary server restarts in the Kerberos TAP test |
| Previous Message | Michael Paquier | 2026-08-03 04:51:17 | Re: Avoid unnecessary server restarts in the Kerberos TAP test |