| From: | Ayush Tiwari <ayushtiwari(dot)slg01(at)gmail(dot)com> |
|---|---|
| To: | PostgreSQL Hackers <pgsql-hackers(at)postgresql(dot)org>, Álvaro Herrera <alvherre(at)kurilemu(dot)de> |
| Subject: | Caching a partition index's parent OID in the relcache? |
| Date: | 2026-07-17 13:41:51 |
| Message-ID: | CAJTYsWUV3Tz5A161y2EcCMqnmCYqKNm6Jt=rXCx9bEOJ-hqL=A@mail.gmail.com |
| Views: | Whole Thread | Raw Message | Download mbox | Resend email |
| Thread: | |
| Lists: | pgsql-hackers |
Hi,
While poking at INSERT ... ON CONFLICT on partitioned tables,
get_partition_ancestors() kept showing up in profiles, it scans
pg_inherits once per hierarchy level, and ExecInitPartitionInfo() calls
it once per leaf-partition index while sorting out arbiter indexes.
There's already an XXX in that loop wondering about a syscache "or some
other way to cache".
I tried the "other way": keep the immediate parent OID on the relcache
entry (a lazily-filled rd_partparent), then use the existing walker above
that. This avoids repeatedly scanning the leaf link and eliminates the
pg_inherits scan entirely for the common one-level hierarchy. Patch
attached (fairly small).
Invalidation uses the existing pg_class relcache events. ATTACH and
DETACH update the child index's relispartition flag, while REINDEX
CONCURRENTLY swaps that flag between the old and replacement index;
creation and drop replace the relation altogether. One detail is that an
open index takes RelationReloadIndexInfo() rather than the full relcache
rebuild path, so the patch clears rd_partparent there as well. No explicit
pg_inherits invalidation is needed.
Quick numbers (256-leaf table, one upsert touching every leaf per statement,
median per-statement latency over 10 warm-session runs):
indexes/table master patched speedup
1 3.17 ms 2.35 ms 1.3x
8 10.18 ms 5.51 ms 1.8x
16 22.40 ms 7.70 ms 2.9x
To be upfront, that's the warm case, a cold first statement still scans
pg_inherits once per index, so it's really repeated upserts that benefit.
Measured on an Azure Standard_D32as_v5 (AMD EPYC 7763, 32 vCPU) under WSL2,
-O2 build without asserts.
I checked REINDEX CONCURRENTLY (010_index_concurrently_upsert.pl), the
core regression and isolation suites, and added a regression that warms
the cache, moves a partition between two partitioned tables, and repeats
the exercise across a savepoint rollback.
One thing I'm unsure about is whether rd_partparent, as the first "upward"
partition field in RelationData (the rest point downward), is the right
place for this cache.
Does this seem worth pursuing, thoughts?
Thanks,
Ayush
| Attachment | Content-Type | Size |
|---|---|---|
| v1-0001-Cache-partition-index-parent-in-relcache.patch | application/octet-stream | 12.4 KB |
| From | Date | Subject | |
|---|---|---|---|
| Next Message | Daniel Westermann (DWE) | 2026-07-17 14:04:00 | Re: Deprecation warnings on Rocky 10.2 with current dev branch |
| Previous Message | Marcos Pegoraro | 2026-07-17 13:41:06 | Re: [PATCH] Add pg_get_trigger_ddl() to retrieve the CREATE TRIGGER statement |