{"post":{"slug":"slow-query-logs-2026","title":"Slow Query Logs: Finding What Is Actually Costing You","excerpt":"The slowest query is rarely the most expensive one. A query taking 40ms and running ten thousand times a minute costs more than one taking four seconds once an hour.","category":"code","date":"January 15, 2026","author":"ByteLedger Team","content":"<span class=\"dropcap\">S</span>omeone opens the slow query log looking for the cause of a performance problem. At the top is a report taking four seconds, run once an hour by a scheduled job. It is the slowest thing in the log and it is consuming four seconds of database time per hour.\n\nMeanwhile a query taking 40 milliseconds runs ten thousand times a minute, consuming four hundred seconds of database time per minute. It never appears in the log, because it is fast.\n\n## What changed in 2026\n\n- **Aggregated statistics displaced threshold logs.** Extensions tracking cumulative statistics per normalised query became the primary tool.\n- **Managed platforms exposed them by default.** Query insights became a standard feature rather than something to configure.\n- **Plan capture improved.** Some tooling began capturing plans alongside statistics, removing a manual step.\n- **Parameter logging stayed contentious.** The tension between reproducibility and logging sensitive values persisted.\n\n## Total time is the metric\n\nRank queries by cumulative execution time, not by worst individual duration.\n\n| Query | Duration | Calls/hour | Total/hour |\n| --- | --- | --- | --- |\n| Hourly report | 4 s | 1 | 4 s |\n| Dashboard widget | 200 ms | 500 | 100 s |\n| Session lookup | 40 ms | 600,000 | 24,000 s |\n\nThe session lookup is the problem, and it never appears in a slow query log at any sensible threshold. It is not slow. It is enormous in aggregate.\n\nThat is why aggregated query statistics — which track calls, total time, mean time, and rows per *normalised query* — are the primary tool. They surface exactly this case, which threshold logging is structurally incapable of finding.\n\nNormalisation matters: the extension groups queries by structure with parameters stripped, so ten thousand executions with different values appear as one entry with a call count.\n\n## What a slow query log is still for\n\nAggregated statistics tell you which query shape costs most. They do not tell you what happened in a specific bad execution.\n\nA threshold log catches individual events: the query that took thirty seconds because it hit a lock, or because a parameter matched far more rows than usual. Aggregated statistics average that away.\n\nSo both have a role. Statistics for finding what to optimise; the log for investigating specific incidents.\n\nSet the threshold high enough that logging does not become its own load. A very low threshold on a busy database produces enormous log volume and can measurably slow the system — which is a real, if embarrassing, way to make performance worse while investigating performance.\n\n## Making entries actionable\n\nA logged slow query you cannot reproduce is of limited use.\n\n**Log the parameters** where you can. A normalised query without values cannot be re-run, and the values are frequently the reason it was slow — a parameter matching a million rows rather than ten. This conflicts with keeping sensitive values out of logs, and the usual compromise is logging parameters for non-sensitive queries and redacting elsewhere.\n\n**Capture the plan** for slow executions where your platform supports it. The plan at the time of the slow execution is far more informative than a plan generated later against different data.\n\n**Log the duration and rows returned.** A query returning a million rows is slow for an understandable reason.\n\n**Include enough context to attribute it** — the application, the endpoint, the user if appropriate. A slow query with no owner is hard to prioritise.\n\n## Common mistakes\n\n- **Optimising the slowest query.** Frequently not the most expensive.\n- **Relying only on a threshold log.** Misses high-frequency queries entirely.\n- **Threshold set very low.** Logging becomes the bottleneck.\n- **No parameters logged.** Cannot reproduce.\n- **Not resetting statistics after a change.** Cumulative counters hide the improvement.\n- **Ignoring rows-returned.** Explains many slow queries immediately.\n- **No attribution.** Cannot tell which team owns the problem.\n\n## FAQ\n\n**How do I measure the effect of a fix?**\nReset the statistics after deploying, then compare over a comparable period. Cumulative counters from before the change dilute the result.\n\n**Should I log every query?**\nOn a busy system, no — the volume is unmanageable and the logging itself costs. Aggregated statistics give the overview; the log catches outliers.\n\n**What about queries that are slow only sometimes?**\nAggregated statistics show a high maximum against a low mean, which is the signature. The log then catches individual instances for investigation, and the cause is frequently lock waiting rather than the query itself.\n\n**Does this replace application tracing?**\nNo — application tracing shows which request triggered which queries, which the database cannot know. They complement each other.\n\n## Where to go next\n\nFor the aggregated statistics tooling, read [pg_stat_statements](/blog/pg-stat-statements-2026). For diagnosing a specific slow query, [query planners](/blog/query-planner-explained-2026), and for bounding the damage, [statement timeouts](/blog/statement-timeouts-explained-2026).","hue":305,"metaTitle":"Slow Query Logs: Finding What Is Actually Costing You","metaDescription":"Why the slowest query is rarely the most expensive, how aggregated query statistics beat threshold logs, and what to log to make queries reproducible.","keywords":["slow query log","query statistics","pg_stat_statements","total execution time","query fingerprinting","database profiling","performance investigation","database operations 2026"],"tldr":["**Total time beats worst time** — frequency multiplied by duration is what consumes your database.","**Aggregated statistics beat a log of individual slow queries** — normalised query fingerprints show the real picture.","**A threshold-based log misses the death by a thousand cuts** — fast frequent queries never appear in it.","**Log the parameters or you cannot reproduce it** — a normalised query without values is hard to investigate.","**Skip:** setting the threshold so low that logging becomes the bottleneck. It happens."],"readTime":"4 min read","wordCount":806},"related":[{"slug":"pg-stat-statements-2026","title":"Query Statistics: The First Thing to Enable on a Database","excerpt":"Cumulative statistics per normalised query answer the only question that matters when a database is slow: what is actually consuming it. Nothing else gets you there as fast.","category":"code","date":"January 12, 2026","author":"ByteLedger Team","readTime":"4 min read","hue":306},{"slug":"query-planner-explained-2026","title":"Query Planners: Why Your Index Is Being Ignored","excerpt":"You added the index and the query got no faster. The planner looked at it, estimated it would be slower, and chose a sequential scan. It is often right.","category":"code","date":"August 17, 2026","author":"ByteLedger Team","readTime":"5 min read","hue":310},{"slug":"how-to-profile-slow-code-2026","title":"How to profile slow code in 2026: flamegraphs, tracing, and real fixes","excerpt":"Slow code is rarely where you think it is. This is the 2026 guide to profiling accurately — CPU flamegraphs, memory profiles, and database query analysis.","category":"code","date":"April 17, 2026","author":"ByteLedger Team","readTime":"5 min read","hue":320}],"sameCategory":[{"slug":"bazel-build-explained-2026","title":"Bazel Explained: What Hermetic Builds Actually Cost","excerpt":"Bazel delivers reproducible, precisely cached builds and demands that you describe everything. Here is what you get, what it costs, and who should say no.","category":"code","date":"August 19, 2026","author":"ByteLedger Team","readTime":"3 min read","hue":145},{"slug":"graphql-federation-2026","title":"GraphQL Federation: One Graph, Many Teams","excerpt":"Federation composes independently-owned subgraphs into a single API. Here is what it solves, the operational cost it adds, and when a simpler gateway is enough.","category":"code","date":"August 19, 2026","author":"ByteLedger Team","readTime":"3 min read","hue":300},{"slug":"hermetic-builds-explained-2026","title":"Hermetic Builds Explained: Same Inputs, Same Output","excerpt":"A hermetic build depends only on declared inputs. Here is what that property gives you, the common leaks that break it, and how to move toward it incrementally.","category":"code","date":"August 19, 2026","author":"ByteLedger Team","readTime":"3 min read","hue":130},{"slug":"monorepo-tooling-compared-2026","title":"Monorepo Tooling Compared: What You Actually Need","excerpt":"Monorepo tools solve task orchestration and caching, not repository layout. Here is what each tier provides and how to tell when you have outgrown the simple option.","category":"code","date":"August 19, 2026","author":"ByteLedger Team","readTime":"3 min read","hue":150}],"newer":{"slug":"side-hustle-taxes-guide-2026","title":"Side hustle taxes 2026: 1099-K, Schedule C, and the rules that changed","excerpt":"The $600 1099-K threshold finally arrived in 2026. Here is what side hustlers owe, the deductions to claim, and how to handle PayPal, Venmo, and Etsy.","category":"finance","date":"January 15, 2026","author":"ByteLedger Team","readTime":"3 min read","hue":280},"older":{"slug":"tax-loss-harvesting-guide-2026","title":"Tax-loss harvesting in 2026: the rules, the wash-sale trap, and the math","excerpt":"Tax-loss harvesting can shave thousands off your tax bill — if you understand the wash-sale rule. Here is how it works, who it helps, and the limits.","category":"finance","date":"January 15, 2026","author":"ByteLedger Team","readTime":"4 min read","hue":285}}