Tracing & Performance

How to Find Slow Database Queries in Production

Slow queries hide inside fast-looking endpoints. Learn to use traces and spans to surface the exact query dragging down your API response times.

Your API endpoint responds in 2 seconds. Everything looks fine in your response-time metrics. Then you dig into the traces and discover a single database query is eating 1.8 of those seconds. Finding slow database queries is often the fastest path to cut API latency in half — but only if you can surface them. This guide shows how to use traces and spans to identify the exact queries dragging down your endpoints, then fix them.

Most teams find out about slow queries the hard way: a customer complains, you check metrics, and you see p95 latency has spiked. By then the damage is done. With distributed tracing, you can spot the slow query before it hits production, and catch regressions the moment they ship.

Why slow queries hide in plain sight

An endpoint that talks to the database might make dozens of calls — each one fast on its own, but collectively slow. A 50ms query doesn't stand out in a sea of fast I/O, network calls, and cache hits. But if that query runs 20 times per request, you've just added a full second to your response.

The N+1 query problem is the most common culprit. A simple example: you fetch a list of users, then loop through and fetch each user's posts one at a time. One database call becomes hundreds, and your endpoint goes from 20ms to 5 seconds without any code that looks slow.

Response-time metrics show the total, but not the breakdown. A 2-second endpoint doesn't tell you if 1.8 seconds is database time or external API calls. You need span-level visibility to find out.

How spans expose slow queries

Distributed tracing breaks down a request into spans — each one representing a distinct operation like a database query, an HTTP call, or a cache fetch. When you look at a span waterfall, you see every operation and exactly how long it took.

For databases, this means each query is its own span. You can immediately see which queries are slow, which ones run multiple times, and how much time they consume in aggregate.

Here's what a typical trace waterfall looks like:

Request: GET /api/users/123/dashboard
├─ Database: SELECT * FROM users WHERE id = 123 (45ms)
├─ Database: SELECT * FROM posts WHERE user_id = 123 (89ms)
├─ Database: SELECT * FROM comments WHERE post_id = ? (8ms × 24 queries = 192ms)
├─ Cache miss → API call: POST /external-service (520ms)
└─ Serialize response (12ms)
Total: 858ms

That waterfall tells you everything. The comments query is running 24 times (the N+1 problem), and the external API call is the real bottleneck. Now you know exactly what to fix.

Instrumenting your database to produce spans

To see spans, your database client needs to be instrumented. Most Sentry SDKs do this automatically for popular ORMs and database drivers.

Node.js with Sequelize

import * as Sentry from "@sentry/node";
import { Sequelize } from "sequelize";

Sentry.init({
  dsn: "https://<key>@your-lighttrace-host/1",
  tracesSampleRate: 1.0,
});

const sequelize = new Sequelize("postgres://user:pass@localhost/mydb");

// Sentry automatically instruments Sequelize queries
const posts = await Post.findAll({ where: { userId: 123 } });

Every query to the database is now a span in your trace.

Python with Django

import sentry_sdk
from sentry_sdk.integrations.django import DjangoIntegration
from sentry_sdk.integrations.sqlalchemy import SqlalchemyIntegration

sentry_sdk.init(
    dsn="https://<key>@your-lighttrace-host/1",
    integrations=[
        DjangoIntegration(),
        SqlalchemyIntegration(),
    ],
    traces_sample_rate=1.0,
)

Django ORM queries are automatically instrumented and appear as spans.

Java with Spring Boot

import io.sentry.Sentry;

public class Application {
    static {
        Sentry.init(options -> {
            options.setDsn("https://<key>@your-lighttrace-host/1");
            options.setTracesSampleRate(1.0);
            options.setEnableTracing(true);
        });
    }
}

JDBC queries are instrumented automatically when tracing is enabled.

If your framework isn't auto-instrumented, you can manually create spans for database operations using your SDK's transaction or span API. Check your SDK documentation for the exact method.

Reading a span waterfall to find the culprit

Once traces are flowing, navigate to a slow transaction and open the span waterfall. Here's what to look for:

1. Identify the slowest span. Sort by duration if available, or scan visually. That's usually your target.

2. Check for repeating spans. If a query runs 50 times, each copy is fast but the total is slow. That's textbook N+1.

3. Look at critical path. If query A is fast but runs sequentially before query B, query A still matters because it delays the rest.

4. Cross-check against database time. If database spans total 1.5s but your endpoint took 2s, you have 500ms elsewhere. Investigate external APIs, cache lookups, or serialization.

Common slow-query patterns and fixes

Pattern 1: N+1 queries

Signature: Same query runs many times in a loop.

Fix: Use joins or batch loading. In SQL, replace multiple single-row queries with one query that fetches all rows.

// Bad: N+1 (runs 1 + N queries)
const users = await User.findAll();
for (const user of users) {
  user.posts = await Post.findAll({ where: { userId: user.id } });
}

// Good: One query with a join
const users = await User.findAll({
  include: [{ association: "posts" }],
});

Pattern 2: Full table scans

Signature: A query with no WHERE clause or a missing index on a large table.

Fix: Add an index on frequently-filtered columns.

-- Query is slow because no index on user_id
SELECT * FROM orders WHERE user_id = 123;

-- Add an index
CREATE INDEX idx_orders_user_id ON orders(user_id);

Pattern 3: Unbound result sets

Signature: A query fetches thousands of rows but the application only needs 10.

Fix: Add LIMIT and pagination.

// Bad: Fetches all posts, slows down serialization and network
const posts = await Post.findAll({ where: { published: true } });

// Good: Fetch only what you need
const posts = await Post.findAll({
  where: { published: true },
  limit: 20,
  offset: (page - 1) * 20,
});

Finding the slowest endpoints

Not all queries are created equal. A slow query that runs once per month is less critical than a fast query that blocks your homepage.

Reduce API latency by starting with your slowest and most-trafficked endpoints. In your error tracker's performance section, look for transactions with the highest P95 and P99 latency, then drill into their waterfalls. The combination of high latency and high throughput means fixing it pays dividends.

Focus on P95 and P99, not average. Average latency hides your worst experiences; percentiles show what real users actually encounter.

Monitoring and preventing slow queries

Once you've fixed a slow query, you need a way to catch regressions. Set up an alert rule that fires when the p95 latency of a transaction or span crosses a threshold.

With distributed tracing, you can track not just overall transaction latency, but the latency of individual spans. An alert on "database span duration > 500ms" on your critical endpoints catches regressions before customers do.

You can also use release tags to compare before and after a deploy. If a new release causes database span latency to spike, you'll know immediately and can roll it back.

Without traces, you rely on metrics and guesswork. With them, you have a complete, timestamped record of every operation and exactly how long it took. That's the difference between "our API is slow" and "the posts query is running 24 times on the dashboard endpoint, and we can fix it by adding an eager-load join."

Slow queries are usually the low-hanging fruit in latency optimization. A well-indexed database and eager loading can cut endpoint response times by 50–80%. The trick is seeing them in the first place — and traces make them impossible to miss.

Start tracking errors in minutes

Point any Sentry SDK at LightTrace and start seeing detailed database spans in your trace waterfalls — identify and fix slow queries before they hit production.

The faster your database queries, the faster your API. Start capturing traces today and let your span waterfalls guide the way.

Fix your next production error faster

Point any Sentry SDK at LightTrace — free up to 5,000 events/month.