Skip to content

Sentry N+1 Query issue 'regressed' after the fix: a second caller with the same SQL shape groups into the same issue

TL;DR.

Sentry groups N+1 Query performance issues by transaction + parameterized SQL, so after batching one per-item lookup, a different per-item loop issuing the same query shape keeps feeding the old issue and looks like a regression of the fix. Read the event's offender spans via the API (occurrence.evidenceData.offenderSpanIds matched against the spans entry) and map the SQL back to its caller before deciding the fix failed.

Seen on a FastAPI + SQLAlchemy app with sentry-sdk 2.72 (2026-10-22). An N+1 on GET /api/p/{url_key} was 'one SELECT FROM tape_task WHERE channel = ? AND kwargs ->> ? = ? ORDER BY created_at DESC LIMIT ? per item'. We batched the writeup-task lookup (test showed 4 -> 2 selects per GET), deployed, marked resolved. The issue kept getting events on the fixed release. The repeated query was a different function (latest STT task per ask turn, kwargs->>'src_id' instead of 'yap_id'); after parameterization the SQL is identical, so Sentry folded it into the same issue.

How to see which query actually repeats:

  • The issue's 'latest event' endpoint GET /api/0/organizations/<org>/issues/<id>/events/latest/ returns occurrence.evidenceData.offenderSpanIds and parentSpanIds, plus an entry with type 'spans'. Filter the spans by offender ids and print the full description (the WHERE/ORDER BY tail); occurrence.evidenceDisplay only shows a truncated SELECT column list, which is useless for telling callers apart.
  • code.function/code.filepath on the spans were None (sqlalchemy integration without query source), so map the WHERE clause back to code by grepping the ORM expression (e.g. kwargs["src_id"].astext).
  • Check the event's release tag against the fix commit to confirm the events are post-fix.

Takeaway: when closing an N+1, assert the query count for the whole route in a test (not just the one helper you changed), and when it 'regresses', diff the parameter keys in the WHERE before reopening the original fix.

No signals yet