performance_tests.txt
text/plain
Filename: performance_tests.txt
Type: text/plain
Part: 0
Performance Results
===================
Test Environment:
- CPU: Apple M2 Pro (12 cores)
- RAM: 32 GB
- OS: macOS 26.5.1 (darwin 25.5.0, arm64)
- Compiler: Apple clang 21.0.0 (clang-2100.1.1.101)
- PostgreSQL: 19beta1 (built from source, -O2, no --enable-cassert)
- Disk: internal SSD (APFS)
Wall Clock Timing: pg_dump --schema-only (7 runs each, milliseconds)
---------------------------------------------------------------------
Database: perf_baseline
pg_init_privs rows: 249 | user functions/aggs: 0
Unpatched: 49.69 52.29 46.42 49.73 63.11 51.58 53.50
Patched v6: 52.49 50.23 50.02 51.87 48.83 65.23 64.58
Median unpatched: 51.58 ms
Median patched: 52.49 ms
Delta: +0.91 ms (+1.8%)
Database: perf_10k_functions
pg_init_privs rows: 249 | user functions/aggs: 10500
Unpatched: 1619.04 1674.27 1638.30 1598.82 1597.56 1613.76 1591.44
Patched v6: 1582.23 1584.01 1657.28 1598.13 1573.98 1576.01 1572.51
Median unpatched: 1613.76 ms
Median patched: 1582.23 ms
Delta: -31.53 ms (-2.0%) [within noise, patched is NOT slower]
Database: perf_dangling_500
pg_init_privs rows: 749 (500 dangling) | user functions/aggs: 500
Unpatched: 107.28 104.59 104.23 102.89 102.20 96.26 102.95
Patched v6: 103.90 105.64 104.61 105.18 106.71 105.50 107.20
Median unpatched: 102.95 ms
Median patched: 105.50 ms
Delta: +2.55 ms (+2.5%)
Summary Table:
| Database | initprivs rows | Median unpatched | Median patched | Delta |
|--------------------|----------------|------------------|----------------|------------|
| perf_baseline | 249 | 51.58 ms | 52.49 ms | +0.9 ms |
| perf_10k_functions | 249 | 1613.76 ms | 1582.23 ms | -31.5 ms * |
| perf_dangling_500 | 749 | 102.95 ms | 105.50 ms | +2.6 ms |
* Negative delta = within measurement noise; the patch does NOT slow
down large-schema dumps.
EXPLAIN ANALYZE: getAdditionalACLs() Query Isolation
-----------------------------------------------------
Database: perf_baseline (249 rows, no dangling entries)
Unpatched:
Seq Scan on pg_init_privs (actual time=0.005..0.014 rows=249 loops=1)
Buffers: shared hit=3
Planning Time: 0.198 ms
Execution Time: 0.043 ms
Patched v6:
Seq Scan on pg_init_privs pip (actual time=0.042..1.037 rows=249 loops=1)
Buffers: shared hit=5
SubPlan array_1
-> Function Scan on unnest elt (actual time=0.003..0.003 rows=1.65 loops=249)
SubPlan exists_1
-> Function Scan on aclexplode ace (actual time=0.001..0.001 rows=0 loops=411)
SubPlan exists_3
-> Seq Scan on pg_authid (rows=18 loops=1) [hashed]
SubPlan exists_5
-> Seq Scan on pg_authid (rows=18 loops=1) [hashed]
Planning Time: 0.620 ms
Execution Time: 1.082 ms
Overhead: +1.04 ms (one-time cost at dump startup)
Database: perf_dangling_500 (749 rows, 500 dangling entries)
Unpatched:
Seq Scan on pg_init_privs (actual time=0.005..0.032 rows=749 loops=1)
Buffers: shared hit=9
Planning Time: 0.230 ms
Execution Time: 0.069 ms
Patched v6:
Seq Scan on pg_init_privs pip (actual time=0.038..2.174 rows=749 loops=1)
Buffers: shared hit=96
SubPlan array_1
-> Function Scan on unnest elt (actual time=0.002..0.002 rows=0.55 loops=749)
Rows Removed by Filter: 1
SubPlan exists_1
-> Function Scan on aclexplode ace (actual time=0.001..0.001 rows=0.55 loops=911)
SubPlan exists_3
-> Seq Scan on pg_authid (rows=18 loops=1) [hashed]
SubPlan exists_5
-> Seq Scan on pg_authid (rows=18 loops=1) [hashed]
Planning Time: 0.517 ms
Execution Time: 2.225 ms
Overhead: +2.16 ms (worst case: 500 dangling entries filtered)
Key observation: pg_authid is scanned ONCE and hashed (loops=1). The
hashed subplan is reused for all 749 rows, making the overhead O(n) in
pg_init_privs rows with a very small constant.
EXPLAIN ANALYZE: getAggregates WHERE Clause (UNCHANGED)
--------------------------------------------------------
Database: perf_10k_functions (500 user aggregates, 10000 user functions)
Hash Left Join (actual time=1.004..1.113 rows=500 loops=1)
Hash Cond: (p.oid = pip.objoid)
Filter: (p.pronamespace <> ... OR p.proacl IS DISTINCT FROM pip.initprivs)
Rows Removed by Filter: 163
Buffers: shared hit=348
-> Seq Scan on pg_proc p (actual time=0.039..1.029 rows=663 loops=1)
Filter: (prokind = 'a')
Rows Removed by Filter: 13274
-> Hash (actual time=0.022..0.022 rows=69 loops=1)
-> Seq Scan on pg_init_privs pip (actual time=0.010..0.013 rows=69 loops=1)
Filter: (classoid = 1255 AND objsubid = 0)
Rows Removed by Filter: 180
Planning Time: 0.834 ms
Execution Time: 1.168 ms
This query is byte-for-byte IDENTICAL in patched and unpatched code.
The patch does NOT modify any WHERE clause. Timing is identical.
The filtering adds ~1ms (249 rows) to ~2ms (749 rows) to the one-time
getAdditionalACLs() query that runs at pg_dump startup. This is a fixed
cost that does NOT scale with the number of functions, aggregates, or
other objects in the database.
The critical performance test is perf_10k_functions (10,000 functions +
500 aggregates): the patched version shows NO regression. The median is
actually 31ms faster, which is just noise. The per-object queries
(getAggregates, getFuncs) are completely unchanged and produce identical
execution plans.