SQL Formatter khi review PR & log ORM | Pretty-print trước EXPLAIN
Trước khi tranh luận index hay đổ lỗi ORM, hãy pretty-print SQL. Log một dòng từ Prisma / Eloquent / TypeORM che mất JOIN và điều kiện — format xong mới đọc EXPLAIN mới hiệu quả. Team outsourcing nên thống nhất: keyword HOA + indent theo mệnh đề; dùng Định dạng SQL trên trình duyệt khi review PR hoặc dán log nhạy cảm (không upload DB production lên dịch vụ lạ).
Outsourcing và freelancer backend ở Việt Nam review PR hàng ngày với SQL đến từ query builder / ORM, không phải file .sql viết tay. Reviewer mở diff thấy:
const users = await prisma.user.findMany({ include: { orders: true }, where: { ... } });
Nhưng bug nằm ở SQL thật ORM sinh ra — thường chỉ xuất hiện khi bật log: một dòng SELECT ... JOIN ... WHERE ... dài hàng nghìn ký tự. Bảo “nhìn EXPLAIN” mà chưa format = đoán mò.
Bài viết này giúp bạn
- Hiểu khi nào pretty-print quan trọng hơn chỉnh ORM
- Áp dụng convention cho team nhiều quốc gia / nhiều style
- Phân biệt Format vs Minify
- Gắn SQL đã format vào PR / ticket / post-mortem
- Tránh paste secret và PII lên tool online không rõ nguồn
Pain: ORM log một dòng
Ví dụ (rút gọn) giống log thật:
select u.id, u.name, o.order_date, p.product_name from users u join orders o on u.id = o.user_id join products p on o.product_id = p.id where o.status = 'completed' and o.created_at > '2025-01-01' order by o.created_at desc limit 100;
Ở dạng này, reviewer khó trả lời nhanh:
- Có JOIN products có cần không nếu chỉ đếm order?
created_atđã có index chưa?LIMITcó đi vớiORDER BYổn không?
Sau khi format:
SELECT
u.id,
u.name,
o.order_date,
p.product_name
FROM
users u
JOIN orders o ON u.id = o.user_id
JOIN products p ON o.product_id = p.id
WHERE
o.status = 'completed'
AND o.created_at > '2025-01-01'
ORDER BY
o.created_at DESC
LIMIT
100;
Cấu trúc lộ ngay: hai JOIN, hai điều kiện, sort + limit. Bước mắt này nên đứng trước EXPLAIN — plan không thay thế việc hiểu query đang làm gì.
Format vs Minify vs “để nguyên log”
| Chế độ | Dùng khi | Không dùng khi |
|---|---|---|
| Format (pretty) | Review PR, debug chậm, viết ticket, đọc trước EXPLAIN | Nhúng vào chuỗi một dòng trong shell thô |
| Minify (1 dòng) | Gán vào biến script, một số tool CLI, so sánh hash chuỗi | Lưu trong repo để người đọc |
| Log thô ORM | Chỉ để copy nhanh từ console | Paste thẳng vào PR không format |
Convention gợi ý cho team outsourcing
Ghi vào CONTRIBUTING.md hoặc wiki ngắn:
- KEYWORD viết HOA —
SELECT,FROM,JOIN,WHERE,AND,ORDER BY - Mỗi cột một dòng khi SELECT > 3 cột
- JOIN và ON cùng khối nhìn thấy điều kiện gắn kết
- AND/OR căn lề dưới WHERE
- Ticket hiệu năng đính SQL đã format + plan (text hoặc ảnh)
Không cần tranh “comma-first vs comma-end” nếu team chưa pain — chọn một và giữ ổn định quan trọng hơn.
Workflow: từ log ORM → EXPLAIN
- Bật log trên staging (Prisma
query, Laravel telescope/DB::listen, TypeORMlogging). - Reproduce đúng API/job chậm.
- Copy SQL — nếu log còn
?placeholder, bind giá trị mẫu an toàn (không phải production secret). - Format bằng Định dạng SQL Kawa (Format + tùy chọn viết hoa từ khóa).
- Đọc cấu trúc 30–60 giây: bảng nào, filter nào, sort nào.
- EXPLAIN / EXPLAIN ANALYZE trên bản đã hiểu.
- Sửa ở đúng lớp: index,
selectthừa, N+1, hoặc rewrite query.
Công cụ chạy trong trình duyệt — phù hợp khi SQL có tên bảng nội bộ; vẫn nên che email/SĐT/token trước khi chia sẻ screenshot.
🗃️ Định dạng SQL ngay tại đây
Case study 1: PR “thêm filter” làm chậm list đơn hàng
Bối cảnh: Team VN outsource cho client JP. Dev thêm where: { status, shopId, createdAt } trong Prisma. API list từ 80ms → 1.2s trên staging.
Sai: Mở thẳng EXPLAIN trên chuỗi một dòng, tranh luận index status trong khi bỏ sót JOIN bảng shops không dùng trong SELECT.
Đúng: Format → thấy JOIN shops thừa từ include cũ. Bỏ include, thêm composite index (shop_id, created_at). PR mô tả kèm SQL pretty — reviewer approve trong một vòng.
Case study 2: Hai dev, hai style SQL trong cùng service
Một người viết keyword thường, người kia HOA; một người indent subquery kiểu C, người kia để một dòng. Diff Git gần như không đọc được dù logic giống nhau.
Fix quy trình: Mọi raw SQL trong *.sql / string dài phải format trước khi commit; CI không bắt buộc formatter SQL, nhưng checklist PR có mục “SQL đã pretty?”. Dùng chung tool browser khi pair remote — không cãi IDE plugin khác nhau.
Khi formatter “hỏng” output
- Quote chưa đóng / ngoặc lệch → sửa tay trước.
- Dialect riêng (hint SQL Server,
::jsonbPostgres phức tạp) — format có thể không đẹp hoàn hảo; vẫn đủ để đọc khối chính. - Query cực lớn (DDL hàng nghìn dòng) — tách phần đang debug; đừng dán cả dump.
Formatter không thay linter SQL hay migration tool. Nó thay bước đọc bằng mắt.
Checklist gắn vào PR hiệu năng / raw SQL
- SQL trong mô tả PR đã pretty-print
- Keyword theo convention team
- Đã che PII / secret
- Có EXPLAIN (hoặc lý do chưa chạy được)
- Nêu giả thuyết: index / JOIN thừa / N+1 / sort file
Công cụ liên quan
- Định dạng SQL — Format, Minify, viết hoa từ khóa
- Định dạng JSON — khi log API trả plan/json phụ
- YAML ↔ JSON — config CI/DB sidecar, không thay SQL
SQL chậm không chờ “cảm giác”. Nhìn thấy cấu trúc rồi mới tối ưu — pretty-print là bước rẻ nhất trong chuỗi đó.