Overlap the waiting with concurrency and reduce the number of round trips
If the application is waiting rather than computing, the goal is to overlap waits and reduce the number of waits. The first lever is to reduce round trips: batch queries, use joins or IN clauses instead of N+1 loops, cache hot reads, and select only the columns you need. The second lever is concurrency: an async stack with an async database driver and HTTP client lets one thread keep hundreds of requests in flight, and a thread pool with a synchronous driver is the pragmatic alternative when async drivers are not available. The third lever is pooling: reuse connections and configure pool sizes and timeouts to match the backend's limits. The fourth is timeouts and retries with backoff so slow calls fail fast instead of consuming worker capacity.
Measure first. Identify whether time is in the database, the network, or serialization, using query logs, tracing, and profiling.
Batch and cache: the fastest call is the one you do not make.
Use async drivers or a thread pool. Do not call a blocking driver from an async handler.
Configure connection pools explicitly: max size, idle timeout, and statement timeouts.
Add timeouts on every external call. A missing timeout is a production outage waiting to happen.
Trade-off: higher concurrency improves throughput but increases load on downstream systems and complicates debugging.
Common mistake: increasing worker count to mask a slow query. That multiplies load on the database.
Version note: asyncpg and psycopg 3 async support are the modern choices for PostgreSQL. httpx and aiohttp are standard async HTTP clients.
0-2 years experience
2-5 years experience
5-8 years experience
8+ years experience