Three seconds on the clock is rarely three seconds of work. It's three seconds of waiting for a resource something else is holding.
The pattern I hit most often in payment and verification endpoints: a database transaction opened at the top of the handler, then an outbound call to a provider made inside that transaction. Nothing is computing. A connection sits pinned while a third party decides how fast it wants to answer.
Give that a modest pool and a provider having a bad minute, and the pool drains. Now endpoints that touch no provider at all start queueing on connection acquisition. In your timings it surfaces as slow SQL or slow views, so you go optimize a query that was never the problem. The slow thing was not the thing doing work.
So before I touch indexes, I check one thing: does any request path hold a transaction across a network boundary I don't control? If yes, that's the three seconds, and no amount of query tuning will move it.
What fixes it is boundary discipline, which isn't performance work at all. Write local state, commit, then call out. Treat the provider's answer as a separate state transition with its own retry path and its own idempotency key. The handler gets fast again because it stops owning someone else's latency.
And measure acquisition wait separately from execution time. A saturated pool and a genuinely slow query look identical in average response time and have nothing in common: one is a concurrency bug, the other is a data-access bug.
I write up more of these production trade-offs on my blog: https://polycratia.com/c/1f535fc1
Somewhere in your request path, a transaction is probably still open across a call you don't control...