Database (N+1 and slow query)¶
TL;DR. Statements-per-request counter + slow-query span events, sourced from the Spring 6.2 DB Observation. Catches N+1s in PromQL instead of in a tail-latency post-mortem.
The N+1 query bug is the most common Spring/JPA performance footgun, and it's invisible to most observability stacks because each individual statement looks fine — it's the count per request that matters.
Pulse counts statements per request. When one route accidentally fires fifty queries, you see it in a metric instead of in a tail-latency investigation.
What you get¶
Any non-zero result is a route that crossed the threshold (default 50 statements per request) at least once in the window. The shipped alert points straight at the endpoint.
You also get the per-request distribution itself, so you can spot drift over time:
Turn it on¶
Nothing — automatic when Hibernate ORM is on the classpath.
To raise or lower the threshold:
What it adds¶
| Metric / signal | Meaning |
|---|---|
pulse.db.statements_per_request |
Distribution summary, prepared statements per request |
pulse.db.n_plus_one.suspect (tag endpoint) |
Counter — fires when the threshold trips |
Span event pulse.db.n_plus_one.suspect |
Marks the offending request in the trace |
WARN log (one-time per endpoint per minute) |
Surfaces it without scraping Prometheus |
Slow queries flow through Hibernate's built-in org.hibernate.SQL_SLOW
logger, automatically correlated with the trace by Pulse's structured
logs layout.
When to skip it¶
If you already use p6spy, Datadog APM, or another query-counting layer:
Conditional gating¶
To suppress N+1 detection for known-chatty admin endpoints (bulk imports,
batch reconciliation jobs that legitimately fire hundreds of statements)
without raising the global threshold, use
enabled-when:
Requests excluded by the matcher don't open the per-request statement
scope at all — no pulse.db.* metrics, no warning, no trace event.
Source: io.github.arun0009.pulse.db ·
Status: Stable since 1.0.0