Ugly SQL Survives Code Review — Formatted Queries Do Not Hide Cross Joins

(Updated: July 16, 2026 ) SQL sql formatter code review databases webdev

The PR adds a “simple” report endpoint. The ORM log is one 8,000-character line. Two reviewers approve green CI. Production CPU melts on the first real customer because a missing ON clause produced a cartesian product. Nobody saw it — not because they were careless, but because the SQL was unreadable.

Formatting as a review surface

Pretty SQL makes structure obvious:

SELECT
  o.id,
  c.email,
  SUM(i.amount) AS total
FROM orders AS o
JOIN customers AS c
  ON c.id = o.customer_id
JOIN order_items AS i
  ON i.order_id = o.id
WHERE o.created_at >= $1
GROUP BY o.id, c.email;

The same query as a single line hides the join intent. Reviewers scan for:

  • Join conditions present for every table
  • Filters that match the product story (deleted_at, tenant_id)
  • Aggregations that match GROUP BY
  • OR conditions that disable indexes accidentally
  • Subqueries that could be windows or CTEs for clarity

ORM culture without shame

ORMs are fine. Blind trust in generated SQL is not. For any query that touches more than two tables or wraps reporting:

  1. Log SQL in the feature branch.
  2. Format it with a SQL formatter.
  3. Paste the formatted form into the PR (or attach explain output).
  4. Run EXPLAIN / EXPLAIN ANALYZE on realistic data volumes.

Dialect matters (Postgres vs MySQL vs BigQuery). Formatters that understand your dialect keep keywords and functions from becoming noise.

Maintainability beyond the first merge

Six months later someone adds a column. If the team’s habit is formatted CTEs with named steps, the change is local. If the habit is nested subselects in one line, every edit is archaeology. Adopt a house style:

  • Uppercase keywords or lowercase — pick one
  • One column per line in wide selects
  • Explicit AS aliases
  • CTEs for multi-step reports instead of nested soup

Put the formatter in editor save or CI for .sql migration files. Application strings are harder; at least format when reviewing.

Logging without leaking

Format for humans, but bind parameters stay out of the SQL string when possible. If you must interpolate for a ticket, redact emails and tokens. Readable SQL in an error tracker is worthless if it contains session cookies.

Diffs and blame

Formatted SQL produces meaningful git blame. A one-line monster attributes the entire query to whoever last touched a comma. Encourage migrations and report queries to live in .sql files or clearly delimited raw strings so formatters and linters can run. Some teams forbid multi-table queries inside application code without an accompany EXPLAIN screenshot in the ticket — harsh, but effective after one outage.

When comparing plans across environments, paste the same formatted text so reviewers are not arguing about whitespace. Store EXPLAIN output next to the query in the wiki for expensive paths; update it when indexes change.

Soft rules for ORMs

  • Prefer explicit selects for list endpoints
  • Watch default JOIN strategies that eager-load graphs you do not need
  • For reports, a readable SQL view or CTE often beats a clever repository method

Formatting will not invent an index. It will make the missing WHERE tenant_id = ? obvious enough that someone asks before merge — which is the entire maintainability win.

What formatting will not save: bad indexes, N+1 call patterns, and selecting blobs you do not need. Formatting makes those problems visible. Visibility is the point of maintainable SQL — the planner does not care about newlines, but your teammates (and future you at 2 a.m.) absolutely do.