The intuition is that more concurrency means more throughput. Past the hardware's
capacity, the opposite happens, and the shape of the curve is worth carrying. The
figures below are illustrative of that shape rather than a measurement of any
particular system — the absolute numbers depend entirely on your hardware and
workload, and only the direction of each column generalises.
16-core database server, mostly CPU-bound workload
pool size throughput p99 latency
--------- ------------- -----------
16 ~12,000 tps 14ms
32 ~12,400 tps 28ms queueing, no more work done
100 ~11,800 tps 95ms context switching, lock contention
400 ~9,200 tps 480ms worse on every axis
Beyond the point where every core is busy, additional connections do not add
capacity — they add a queue. Worse, they add it inside the database, where you
cannot see it, instead of in the pool where you could have measured it. The extra
connections also each consume memory for sort and hash workspace, so a large pool
can turn in-memory sorts into disk spills.
A common starting formula is cores x 2 + effective spindle count, which for
sixteen cores and SSD storage lands somewhere near thirty-five, not four hundred.
Treat it as a starting point to measure from rather than a rule.
Two consequences for architecture. Queue in the application, where the wait is
visible and you can time it out, rather than in the database. And with many
application instances the pool is per instance, so twenty pods at fifty
connections is a thousand connections to a server sized for forty — which is why
a shared external pooler exists, and why "we scaled out the app and the database
fell over" is such a common story.