Skip to content

PLANETSCALE 2022-06-29 Tier 3

Read original ↗

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

  1. 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_enabled so the gem is no longer required for the default case.

  2. Rails's default tag format is not SQLCommenter. Rails 7's built-in query_log_tags emits /*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 and key='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).

  3. PlanetScale ships activerecord-sql_commenter to bridge the gap. Adding gem "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).

  4. Three config.active_record.* settings constitute the enable envelope. query_log_tags_enabled = true turns the feature on; query_log_tags = [:application, :controller, :action, :job] selects which built-in tags to emit; cache_query_log_tags = true memoises the rendered tag string so per-request tag rendering isn't per-query repeated work (Source: config/application.rb snippet in post). The Rails Query Logs documentation is cited as the canonical reference.

  5. ActiveRecord's annotate(...) method adds per-query ad-hoc tags. Rails 7 added annotate on 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."

  6. PlanetScale Insights's >1 sec capture 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.

  7. 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 10000 tagged /*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-27 actor-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_tags emission format for the SQLCommenter format via a single Gemfile entry + the standard Rails config.active_record.query_log_tags_enabled = true envelope.
  • 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_tags for the default case.
  • systems/ruby-on-rails — extended with the Rails 7 query_log_tags + cache_query_log_tags + annotate primitives.
  • systems/planetscale-insights — extended with the 2022-06-29 earliest wiki disclosure of the >1 sec tail-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_rails is the ActiveRecord-migration-runner that talks to PlanetScale's schema-change API; activerecord-sql_commenter is 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) vs key='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 the activerecord-sql_commenter gem.
  • concepts/activerecord-annotate — new canonical wiki page. The Rails 7 annotate method on ActiveRecord relations for per-query ad-hoc tagging. Orthogonal to query_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:value search-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+), Django django-sqlcommenter (analogous), framework-native hooks in any ORM. Distinct from application-layer tagging (manual annotate(...) 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 is job='ScheduleSnapshotJob' (per-background-job attribution) rather than actor='<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 QueryLogs formatter?), 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 sec capture 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_tags is 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_commenter gem) + extending the patterns/actor-tagged-query-observability pattern's Seen-in timeline backward by three months. Originally marked ingested: true + skip_reason: batch-skip — marketing/tutorial slug pattern by tools/batch_skip_marketing.py; overridden by explicit user request for full ingest.

Source

Last updated · 378 distilled / 1,213 read