🔀ORM vs raw SQL
Productivity vs transparency
ORMs accelerate CRUD, migrations, and typed models. Hand-written SQL shines when you need explicit joins, window analytics, bulk paths, or plan stability, where generated SQL becomes opaque or chatty. Healthy teams mix both with clear boundaries, not religious purity.
⚖️Trade-offs
Pick per surface area, review what ships.
| Approach | Strength | Weakness |
|---|---|---|
| ORM | Schema sync, rapid CRUD, vendor integrations | N+1 graphs, heavy joins, hidden transaction scopes |
| Raw SQL + thin mapper | Full control of plans and batching | More manual migration and review discipline |
ORM might emit (simplified)
SELECT * FROM orders WHERE customer_id = 441 LIMIT 25 OFFSET 50;| note |
|---|
| Fine for simple filters, ensure indexes on customer_id |
Hand-tuned analytics query
SELECT date_trunc('week', o.order_date) AS wk, SUM(oi.qty * oi.unit_price) AS revenue
FROM order_items oi
JOIN orders o ON o.order_id = oi.order_id
GROUP BY 1
ORDER BY 1;| wk | revenue |
|---|---|
| 2026-03-31 | 184000 |
| 2026-04-07 | 201500 |
Mystery SQL in production
- ORM fetch graphs exploding into thousands of round trips.
- Transaction boundaries hidden in framework callbacks.
- Vendor-specific ORM SQL that cannot move across databases.
Profile and codify
- Log and profile emitted SQL in staging; add dataloaders or explicit joins for hot paths.
- Keep migrations in checked-in SQL DDL; review raw modules like application code.
- Document where raw SQL is allowed and who owns it.
Boundary
Escape hatches
.raw / string-built fragment is high risk, treat it like skipping the type checker on purpose.Team habit
The failure mode is not “ORM bad”: it is unreviewed generated SQL nobody can explain. Make query plans part of the same PR conversation as code coverage.
TL;DR
ORMs generate SQL for productivity and safety (parameter binding, migrations), but can emit N+1 queries, hidden joins, or lock-heavy updates. Raw SQL gives full control for hot paths and reporting, pair it with code review and explain plans. Best teams mix both: ORM for CRUD, hand-written SQL where latency and cardinality demand it.