Why Adding More Indexes Won’t Fix Your Slow Go Queries (And What Does)
We added the index. The query was still slow.
Why Adding More Indexes Won’t Fix Your Slow Go Queries (And What Does)

We added the index. The query was still slow.
Not marginally slow — slow enough to time out under load. We spent two days reading the query plan, added a composite index, and then added another one. The p99 latency barely moved. That’s when we had to stop and ask the right question: were we even looking at the right problem?
We cut query execution time by 91% over three weeks. None of it came from a new index.
The index was the wrong tool
When you see slow queries in Go, the reflex is to open the query plan, find a missing index, and add it. This works often enough that it becomes a habit. The problem is that a lot of what looks like a slow query isn’t a slow query at all. It’s a slow pattern, generating many queries or requests spending most of their time waiting to even start one.
That’s exactly what we found.
We were using GORM to fetch a list of orders, then inside the handler loop, fetching each order’s line items separately. Classic N+1. We were issuing hundreds of small queries per request, and no index was going to fix that — because the individual queries were already fast. There were just too many of them.
N+1 is invisible until you count
We spotted it by enabling GORM’s debug mode and logging query counts per request. The number was embarrassing. A single API call to fetch 50 orders was generating 51 database round-trips — one for the orders list, one per order for its line items.
The fix was one line:
db.Preload("LineItems").Find(&orders)
That dropped the query count from 51 to 2. You cannot index your way out of 51 round-trip. The round-trip overhead alone will kill you before query execution time becomes relevant.
The connection pool was the real bottleneck
After fixing N+1, we hit a different wall. We added logging to trace what a request was actually doing. The query itself took under 10ms. The request spent the rest of its time waiting for a database connection to free up. Ninety-four percent of total request time was just waiting to start.
We were running sql.DB with default settings. The default MaxOpenConns is 0 — unlimited. In practice, our database server was handling far more concurrent connections than it could manage efficiently, and the overhead dominated request time.
We landed on these settings after measuring at load:
db.SetMaxOpenConns(25)
db.SetMaxIdleConns(10)
db.SetConnMaxLifetime(5 * time.Minute)
The right numbers depend on your database server and workload. For us, this made the system predictable under load instead of degrading suddenly at a threshold we didn’t know existed.
SELECT * in hot paths
The third issue was subtler. Several hot-path handlers were using GORM’s default Find(), which issues SELECT *. Our orders table had 40+ columns, including large text fields for notes and metadata.
Switching to explicit column selection in those paths reduced data transferred per query and freed up both database I/O and Go’s GC overhead from deserializing fat structs into memory.
db.Select("id", "status", "created_at").Find(&orders)
Not every query needs this treatment. But the ones running hundreds of times per minute do.
What to check before you add the next index
When you’re debugging slow Go queries, work through this before reaching for an index.
Count queries per request with debug logging enabled. N+1 is common in codebases where preloading has been added inconsistently as features accumulated.
Check your connection pool configuration. If you haven’t set MaxOpenConns explicitly, you're running without a ceiling — and you won't find out until load exposes it.
Audit SELECT * in hot paths. ORM defaults are convenient during development. They're often wrong in production.
The index we never added? The queries it was meant to help became irrelevant once we fixed the patterns around them. The database was fine. We just weren’t asking it the right questions.
메타데이터
- post_id
- ae0bc05bdf4a
- slug
- why-adding-more-indexes-wont-fix-your-slow-go-queries-and-what-does-ae0bc05bdf4a
- url
- https://medium.com/noob2star/why-adding-more-indexes-wont-fix-your-slow-go-queries-and-what-does-ae0bc05bdf4a
- canonical_url
- https://medium.com/noob2star/why-adding-more-indexes-wont-fix-your-slow-go-queries-and-what-does-ae0bc05bdf4a
- author_url
- https://medium.com/@singhamrit
- status
- ok
- fetched_at
- 2026-06-09 15:37:30