| From: | Dhruv Aron <dhruv(dot)aron(at)gmail(dot)com> |
|---|---|
| To: | pgsql-hackers(at)postgresql(dot)org |
| Cc: | haoyu(dot)huang(dot)68(at)gmail(dot)com, "hlinnaka(at)iki(dot)fi" <hlinnaka(at)iki(dot)fi> |
| Subject: | Restructured Shared Buffer Hash Table |
| Date: | 2026-07-07 18:41:47 |
| Message-ID: | CAAStW3JX_7LcCD1U+89vyMmLreDs0XsBU-JDdFf5PD_Woy1pag@mail.gmail.com |
| Views: | Whole Thread | Raw Message | Download mbox | Resend email |
| Thread: | |
| Lists: | pgsql-hackers |
Hi,
At Databricks, we’ve found that the existing dynahash table structure is
leaving performance gains on the table when it comes to shared buffer
lookups: the multi-level structure (directory, segment, bucket chain,
freelist) appears excessive for the shared buffers and could be simplified
to boost performance and lower memory overhead. As such, we are proposing a
specialized hash table just for this purpose and would appreciate feedback
on this approach.
To give a brief overview, our new table operates primarily on two arrays,
one for the entries and one for the bucket heads, and it enforces the
invariant that *entries[x]* describes the page in buffer *x*. Each entry
stores only a BufferTag and a ‘next’ index (representing the next entry in
the same bucket chain), with each bucket head only storing a ‘head’ index
(representing the first entry in the bucket chain). At a high-level, the
table essentially creates a logical linked list for each bucket on top of
the flat physical arrays.
The attached patch implements this functionality and passes the existing
regression tests; the buf_table.c functions were modified directly, with
bufmgr.c also changed slightly to prevent a race condition. My testing
(helper script also attached) indicates that all three standard hash table
operations (insert, lookup, and delete) generally execute significantly
faster than the existing PG18 dynahash counterparts:
4 GB
Operation
Average Dynahash Execution Time (ns)
Average New Table Execution Time (ns)
Speedup (Dynahash / New Table)
Lookup
77.33
46.50
1.66x
Insert
111.78
86.33
1.29x
Delete
148.73
104.13
1.43x
16 GB
Operation
Average Dynahash Execution Time (ns)
Average New Table Execution Time (ns)
Speedup (Dynahash / New Table)
Lookup
98.18
83.01
1.18x
Insert
198.58
195.30
1.02x
Delete
279.48
274.77
1.02x
I would like to note, however, that this patch is part of a larger effort
around dynamic shared buffers alongside this patch
<https://www.postgresql.org/message-id/CAM1e6U5XDwKYZo6Jj3yD3xpCB4qkhRSQn8upauHt=WhEbK9VZA@mail.gmail.com>
and additional internal functionality to dynamically resize this new shared
buffer table, i.e. adding *and* removing the number of buckets and entry
slots without requiring a restart or total table rehash; I believe the
table should be resized to prevent it from consuming a disproportionate
amount of memory (or being too slow) relative to the size of the shared
buffers, and I would be happy to create a follow-up patch demonstrating
those resizing capabilities. That being said, I would like to emphasize
that I think the changes here offer enough standalone benefits to merit
their own patch.
Thanks,
Dhruv Aron
| Attachment | Content-Type | Size |
|---|---|---|
| restructured_shared_buffer_table.patch | application/octet-stream | 10.4 KB |
| test.diff | application/octet-stream | 24.3 KB |
| From | Date | Subject | |
|---|---|---|---|
| Next Message | Noah Misch | 2026-07-07 18:57:51 | SPLIT/MERGE use of is_internal=true |
| Previous Message | Tomas Vondra | 2026-07-07 18:39:52 | Re: hashjoins vs. Bloom filters (yet again) |