liveBook · Manning

Concurrency

As explained in PostgreSQL Mistakes and How to Avoid Them

Concurrency is the condition in which multiple operations or users access or modify a system at overlapping times.

Concurrency is the number of operations or clients active at overlapping times. In PostgreSQL, raising it is not a free route to parallel work: each connection consumes resources, and excessive concurrent work can reduce throughput while sharply increasing latency. Size concurrency for the workload and host rather than treating a high connection limit as capacity. section 6.13 section 6.3

The tempting mistake is to set max_connections high enough for every client to connect directly. Many mostly idle sessions still impose computational overhead. Active sessions also compete for finite CPU and may contend on shared PostgreSQL objects through Lightweight Locks (LWLocks), so a server can appear busy without completing useful work quickly. section 6.13 section 6.3

Treat concurrency as a measured operating limit:

  • Benchmark several client counts and compare both TPS and latency; a throughput plateau can conceal an overloaded server that is trading response time for concurrency. section 6.3
  • Keep connection counts workload-specific. A stated empirical starting point is no more than four PostgreSQL connections per CPU core, not a universal rule. section 6.3
  • Avoid idle connections where possible; when they cannot be avoided, use a connection pooler aware of PostgreSQL connection semantics, such as PgBouncer in Transaction Mode. section 6.13
  • Find and resolve idle-in-transaction sessions and long-running queries. They can block other queries, delay applications, and postpone or block autovacuum. section 6.13

A 2,000-client benchmark hides overload

A pgbench run with 2,000 clients processed about 352 TPS at 5,535 ms average latency. Reducing clients raised TPS through 250 clients, but latency did not stabilize near 53–56 ms until 32 or 16 clients. The result is not “more clients is faster”: inspect latency alongside TPS to locate a sustainable concurrency level. section 6.3 section 6.3

Table 6.1 Test results showing TPS and latency with various numbers of clients
Number of clients
TPS
Latency average
2,000
352.1
5,535.267 ms
1,500
506.8
2,869.986 ms
1,000
586.1
1,694.616 ms
500
628.4
794.688 ms
250
635.7
392.554 ms
125
556.9
224.411 ms
63
613.0
102.758 ms
32
572.3
55.907 ms
16
301.8
53.009 ms

Compare the TPS plateau with the falling latency across client counts; the table makes the cost of excessive concurrency visible. section 6.3

Concurrency also affects maintenance safety. High transaction rates can outrun autovacuum’s work to prevent XID wraparound, while disabling or weakening autovacuum merely defers the cost into bloat, inaccurate statistics, and forced anti-wraparound work. Reduce avoidable ingestion through batching, reorganization, summarization, or skipping data unlikely to be reused. section 6.13

How PostgreSQL Mistakes and How to Avoid Them covers it

How deep it goes
Explains concurrency through connection overhead, latency/TPS measurements, LWLock contention, and autovacuum consequences without exhaustively detailing internals.
Examples
Uses pgbench runs from 2,000 to 16 clients, reporting TPS and average latency across the tested counts.
What it assumes
Assumes familiarity with PostgreSQL connections, workloads, CPU cores, and basic performance metrics.
What you can do after
Operate/configure PostgreSQL by selecting workload-tested connection limits and avoiding idle or long-running transactions.
How it connects
Connects concurrency with MVCC, LWLocks, connection pooling, autovacuum, XID wraparound, throughput, and latency.

Also explained in

Compare how 23 books explain concurrency →

Related concepts

This explainer was generated by Manning's knowledge graph from the text of PostgreSQL Mistakes and How to Avoid Them. The section links point to the parts of the book it draws on.