PlanetScale — Identifying slow Rails queries with sqlcommenter¶
Summary¶
Mike Coutermarsh + Iheanyi Ekechukwu (PlanetScale, 2022-06-29) publish the
earliest wiki-canonical how-to for enabling
SQLCommenter tags on queries emitted by a Rails application. The post traces
the three-step evolution of per-query source-attribution in Rails —
Marginalia gem (Basecamp, 2013-ish) → Rails 7-native
query_log_tags (2022) → SQLCommenter format
via the new PlanetScale-authored
activerecord-sql_commenter gem — and lands on a three-primitive
application-tier toolkit: convention-driven per-request tags (controller,
action, job) via config.active_record.query_log_tags; ad-hoc per-query
tags via ActiveRecord's Rails 7 annotate method; and tail-query
attribution via PlanetScale Insights's
>1 sec capture threshold.
Key takeaways¶
-
Rails pre-2022 had Marginalia as the dominant query-tagging gem. Basecamp's Marginalia gem added controller / action annotations to every ActiveRecord-issued query — canonical pre-history of Rails-native query tagging (Source: post body). Rails 7 absorbed this into the framework under
query_log_tags_enabledso the gem is no longer required for the default case. -
Rails's default tag format is not SQLCommenter. Rails 7's built-in
query_log_tagsemits/*application:Api,controller:users,action:show*/— a comma-separated key-colon-value shape. SQLCommenter uses/*application='Api',controller='users',action='show'*/with single-quoted values andkey='value'pairs. Both are inert SQL comments; the semantic difference is that SQLCommenter is machine-readable by Google's published spec and is what Insights / Cloud SQL Insights / third-party query-analysis tools parse natively (Source: post body verbatim comparison snippets). -
PlanetScale ships
activerecord-sql_commenterto bridge the gap. Addinggem "activerecord-sql_commenter", require: "active_record/sql_commenter"to the Gemfile swaps Rails's default emission format for the SQLCommenter format without any other application-level changes (Source: systems/activerecord-sql_commenter — GitHub link planetscale/activerecord-sql_commenter). -
Three
config.active_record.*settings constitute the enable envelope.query_log_tags_enabled = trueturns the feature on;query_log_tags = [:application, :controller, :action, :job]selects which built-in tags to emit;cache_query_log_tags = truememoises the rendered tag string so per-request tag rendering isn't per-query repeated work (Source:config/application.rbsnippet in post). The Rails Query Logs documentation is cited as the canonical reference. -
ActiveRecord's
annotate(...)method adds per-query ad-hoc tags. Rails 7 addedannotateon ActiveRecord relations for cases where the built-in per-request tags aren't enough:User.where(name: "iheanyi").annotate("source='user_metrics_runner'")emits the tag as an inline SQL comment attached to that specific query regardless of what controller/action/job is active (concepts/activerecord-annotate). Canonical use case framed by the post: "If you need even more detail for a specific query." -
PlanetScale Insights's
>1 seccapture threshold is the retention economics. The post discloses verbatim: "Any query that takes over 1 second to run will get recorded and tagged with the values you've set in your sql comments." This is the tail-query-capture cost/value trade-off that the later 2022-09-27 debugging-database- errors-with-Insights post canonicalises as the more general "more than 1 second, read more than 10k rows, or resulted in an error" threshold (Source: sources/2026-04-21-planetscale-debugging-database-errors-with-insights). The 2022-06-29 post here is an earlier, narrower disclosure of the same economics — just the slow-query axis, not yet the heavy-rows or error axes. -
Worked PlanetScale production example of the tag-then-filter loop. A slow query from PlanetScale's own Rails API —
SELECT schema_snapshot.* FROM schema_snapshot WHERE schema_snapshot.ready = true AND created_at > :created_at AND schema_snapshot.deleted_at IS NULL ORDER BY schema_snapshot.id ASC LIMIT 10000tagged/*application='ApiBb,job='ScheduleSnapshotJob'*/— is shown as the canonical debugging workflow: "Using Insights and tags on the slow query, we were able to find exactly where this query was coming from. This enabled us to quickly find and fix the issue in our application." Earliest wiki instance of the actor/job-tagged query observability pattern in actual PlanetScale production debugging voice — ~3 months before Rafer Hazen's 2022-09-27actor-tag post (sources/2026-04-21-planetscale-debugging-database-errors-with-insights).
Systems introduced / named¶
- systems/activerecord-sql_commenter — new canonical wiki page.
PlanetScale-authored Ruby gem, open-sourced at
planetscale/activerecord-sql_commenter.
Swaps Rails 7's default
query_log_tagsemission format for the SQLCommenter format via a single Gemfile entry + the standard Railsconfig.active_record.query_log_tags_enabled = trueenvelope. - systems/marginalia-gem — new canonical wiki stub. Basecamp's
Marginalia gem, canonical
pre-Rails-7 way to add controller/action comments to ActiveRecord
queries. Superseded by Rails 7's native
query_log_tagsfor the default case. - systems/ruby-on-rails — extended with the Rails 7
query_log_tags+cache_query_log_tags+annotateprimitives. - systems/planetscale-insights — extended with the 2022-06-29
earliest wiki disclosure of the
>1 sectail-query capture threshold (the narrower predecessor to the later three-axis threshold disclosed on 2022-09-27). - systems/planetscale-rails-gem — adjacent but distinct system.
planetscale_railsis the ActiveRecord-migration-runner that talks to PlanetScale's schema-change API;activerecord-sql_commenteris the query-log-emission-format shim. Both are Rails ecosystem gems PlanetScale ships; they solve orthogonal problems.
Concepts introduced / extended¶
- concepts/sqlcommenter-query-tagging — extended. This post is
the earliest canonical wiki source of SQLCommenter in a Rails
context (2022-06-29) — earlier than the 2022-08-02 Lambert downtime
post's top-level Insights citation. The post establishes the exact
byte-level format difference between Rails's default tag format and
SQLCommenter:
key:value(comma-sep, colon-sep, no quotes) vskey='value'(comma-sep, equals-sep, single-quoted). - concepts/rails-query-log-tags — new canonical wiki page.
Rails 7's native per-request query-annotation mechanism built into
ActiveRecord. Three
config.active_record.*switches, built-in tag vocabulary (application, controller, action, job), pluggable custom tag providers. The default emission format is a Rails-specific convention, not SQLCommenter — switching requires theactiverecord-sql_commentergem. - concepts/activerecord-annotate — new canonical wiki page.
The Rails 7
annotatemethod on ActiveRecord relations for per-query ad-hoc tagging. Orthogonal toquery_log_tags(which covers per-request conventions); complementary escape hatch for per-query overrides. - concepts/query-tag-filter — existing. Reinforced by the
post's debugging workflow (tag-then-filter in Insights to localise a
slow query's source) — the 2022-06-29 post predates the formal
tag:key:valuesearch-syntax canonicalisation in the 2022-09-27 Hazen post but establishes the operational workflow it serves.
Patterns introduced / extended¶
- patterns/query-comment-tag-propagation-via-orm — new canonical
wiki page. ORM-layer instrumentation automatically attaches a SQL
comment carrying structured metadata (controller, action, job, custom
tags) to every query emitted during a request. Canonical instances:
Marginalia (pre-2022 Rails), Rails 7-native
query_log_tags(2022+), Djangodjango-sqlcommenter(analogous), framework-native hooks in any ORM. Distinct from application-layer tagging (manualannotate(...)per query) and from infrastructure-layer tagging (driver-level or extension-level auto-tags set at lower tiers). - patterns/actor-tagged-query-observability — extended. The
2022-06-29 post is the earliest wiki instance of this pattern in
PlanetScale's own production-debugging voice — ~3 months before the
2022-09-27 Hazen
actor-tag post that becomes the canonical disclosure. Here the tag carried isjob='ScheduleSnapshotJob'(per-background-job attribution) rather thanactor='<user>'(per-authenticated-principal), but the structural shape is identical: tag the query at the ORM layer, see the tag on the slow-query observability surface, localise the offending code path without additional instrumentation.
Operational numbers / thresholds¶
- Insights capture threshold (2022-06-29 disclosure): "any query that takes over 1 second to run will get recorded and tagged." Narrower than the later 2022-09-27 disclosure (">1 sec OR >10k rows OR error"); both refer to the same tail-capture economics primitive, with the 2022-09-27 post broadening the capture axis from just-slow to slow/heavy/failed.
Caveats / scope¶
- Tutorial voice, not architectural deep-dive. No disclosure of
how the gem itself is implemented (monkey-patch? subscriber? custom
QueryLogsformatter?), no benchmarks, no production telemetry beyond the one worked slow-query example. - Rails-only coverage. The post makes no claim about Django, Laravel, or other frameworks' SQLCommenter integration; those live in the open-source SQLCommenter ecosystem (Google's spec + per-language drivers).
- No cardinality-reduction discussion. The
>1 seccapture threshold is the only cost mitigation named. Tag cardinality (controller × action × job combinatorics) isn't discussed — canonicalised later by the 2026-03-24 Hazen enhanced-tagging post (sources/2026-04-21-planetscale-enhanced-tagging-in-postgres-query-insights). - No Insights architecture exposure. The post is a how-to on enabling tags, not a disclosure of Insights internals — those are the 2026-03-24 Hazen post's domain.
- Re-surface date ambiguity: original byline 2022-06-29, RSS
re-fetched 2026-04-21. Content is still current — Rails 7
query_log_tagsis the default in all later Rails versions; the PlanetScale gem is still maintained. - Tier-3 disposition: Tier-3 tutorial post at narrow altitude —
passes Tier-3 scope filter decisively on being the earliest
wiki-canonical source for SQLCommenter in Rails + naming a
previously-uncanonicalised system (the
activerecord-sql_commentergem) + extending the patterns/actor-tagged-query-observability pattern's Seen-in timeline backward by three months. Originally markedingested: true+skip_reason: batch-skip — marketing/tutorial slug patternbytools/batch_skip_marketing.py; overridden by explicit user request for full ingest.
Source¶
- Original: https://planetscale.com/blog/identifying-slow-rails-queries-with-sqlcommenter
- Raw markdown:
raw/planetscale/2026-04-21-identifying-slow-rails-queries-with-sqlcommenter-dac27c33.md
Related¶
- systems/activerecord-sql_commenter
- systems/marginalia-gem
- systems/ruby-on-rails
- systems/planetscale-insights
- systems/planetscale-rails-gem
- concepts/sqlcommenter-query-tagging
- concepts/rails-query-log-tags
- concepts/activerecord-annotate
- concepts/query-tag-filter
- patterns/query-comment-tag-propagation-via-orm
- patterns/actor-tagged-query-observability
- companies/planetscale