Claude Code PostgreSQL migrations: prompts cho thay đổi an toàn
Học cách viết prompt cho Claude Code để thực hiện migrations PostgreSQL an toàn: mẫu expand-contract, backfill, kế hoạch rollback và những kiểm tra cần làm ở staging trước khi phát hành.

Điều gì làm cho thay đổi schema PostgreSQL trở nên rủi ro
Một thay đổi schema PostgreSQL trông đơn giản cho đến khi gặp lưu lượng thực và dữ liệu thực. Phần rủi ro thường không phải là SQL, mà là khi mã app, trạng thái database và thời điểm triển khai không còn khớp nhau.
Hầu hết thất bại là thực tế và đau đầu: một deploy hỏng vì mã cũ chạm tới cột mới, một migration khóa một bảng nóng và số timeout tăng vọt, hoặc một thay đổi “nhanh” im lặng xóa hoặc ghi đè dữ liệu. Ngay cả khi không có crash, bạn có thể đưa ra lỗi tinh vi như default sai, constraint bị vỡ, hoặc index chưa kịp xây xong.
Các migration do AI sinh ra thêm một lớp rủi ro nữa. Công cụ có thể tạo SQL hợp lệ nhưng vẫn không an toàn cho workload, quy mô dữ liệu hoặc quy trình phát hành của bạn. Chúng cũng có thể đoán sai tên bảng, bỏ sót các khóa chạy lâu, hoặc lờ đi rollback vì down migrations khó. Nếu bạn dùng Claude Code cho migrations, bạn cần rào chắn và ngữ cảnh cụ thể.
Khi bài viết này nói một thay đổi là “an toàn”, nó có ba nghĩa:
- Tương thích ngược: các phiên bản app cũ và mới có thể chạy trong suốt rollout.
- Có thể quan sát: bạn có thể đo lường tiến độ và phát hiện vấn đề nhanh.
- Có thể đảo ngược: bạn có kế hoạch rollback có thể thực hiện dưới áp lực.
Mục tiêu là làm cho migrations trở thành công việc thường nhật: dự đoán được, có thể kiểm tra và nhàm chán.
Quy tắc an toàn trước khi bạn viết bất kỳ prompt nào
Bắt đầu với vài quy tắc bất di bất dịch. Chúng giúp model tập trung và giúp bạn không phát hành thay đổi chỉ chạy trên laptop.
Tách công việc thành các bước nhỏ. Một thay đổi schema, một backfill dữ liệu, một thay đổi app và một bước dọn dẹp là các rủi ro khác nhau. Gộp chúng lại khiến khó phát hiện chỗ hỏng và khó rollback.
Ưu tiên thay đổi bổ sung trước khi làm tiêu cực. Thêm cột, index hoặc bảng thường rủi ro thấp. Đổi tên hoặc drop object là nơi dễ xảy ra sự cố. Làm phần an toàn trước, chuyển app, rồi chỉ khi chắc chắn không còn dùng mới loại bỏ cái cũ.
Làm cho app chịu được hai dạng schema trong một thời gian. Code nên có khả năng đọc cả cột cũ lẫn cột mới trong suốt rollout. Điều này tránh cuộc đua khi một số server chạy code mới trong khi database vẫn cũ (hoặc ngược lại).
Đối xử với migrations như code production, chứ không phải script nhanh. Ngay cả khi bạn xây với nền tảng như Koder.ai (backend Go với PostgreSQL, cộng với client React hoặc Flutter), database được chia sẻ cho mọi thứ. Sai lầm rất đắt đỏ.
Nếu bạn muốn một tập quy tắc ngắn để đặt ở đầu mọi yêu cầu tạo SQL, dùng kiểu như:
- Một thay đổi mỗi migration: mở (expand), rồi backfill, rồi chuyển app, rồi dọn dẹp.
- Tránh khóa dài: dùng tạo index CONCURRENTLY và cập nhật theo lô nhỏ.
- Yêu cầu kế hoạch rollback cho mỗi bước, bao gồm cách dừng giữa chừng khi backfill.
- Yêu cầu truy vấn xác minh và chỉ số thành công (số hàng, tỉ lệ null, thời gian).
- Yêu cầu runbook: cách chạy, những gì cần giám sát và ai sẽ được gọi.
Một ví dụ thực tế: thay vì đổi tên cột mà app phụ thuộc, hãy thêm cột mới, backfill chậm, deploy code đọc mới rồi fallback về cũ, và chỉ sau đó xóa cột cũ.
Những gì nên đưa vào prompt để Claude Code không bị lệch hướng
Claude có thể viết SQL khá tốt từ yêu cầu mơ hồ, nhưng migration an toàn cần ngữ cảnh. Đối xử prompt như một brief thiết kế nhỏ: cho thấy hiện trạng, giải thích điều gì không được phá vỡ và định nghĩa “an toàn” cho rollout của bạn.
Bắt đầu bằng việc dán chỉ các sự thật database có liên quan. Bao gồm định nghĩa bảng cùng các index và constraint quan trọng (primary key, unique, foreign key, check, trigger). Nếu có bảng liên quan, dán các đoạn đó nữa. Một trích đoạn nhỏ và chính xác ngăn model đoán tên hoặc bỏ sót constraint quan trọng.
Thêm qui mô thực tế. Số hàng, kích thước bảng, tốc độ ghi và lưu lượng đỉnh ảnh hưởng kế hoạch. “200M rows và 1k writes/sec” khác nhiều so với “20k rows và chủ yếu đọc.” Cũng cho biết phiên bản Postgres và cách migrations chạy trong hệ thống của bạn (một transaction hay nhiều bước).
Mô tả cách ứng dụng sử dụng dữ liệu: các truy vấn read/write quan trọng và các background job. Ví dụ: “API đọc theo email”, “worker cập nhật status”, hoặc “report scan theo created_at”. Đây là yếu tố quyết định bạn cần expand/contract, feature flags, và mức an toàn của backfill.
Cuối cùng, rõ ràng về ràng buộc và kết quả mong muốn. Một cấu trúc đơn giản hiệu quả:
- Đoạn schema hiện tại và mục tiêu
- Giả định qui mô (số hàng, writes/sec, cửa sổ bảo trì nếu có)
- Phụ thuộc app (truy vấn/endpoint/job)
- Ràng buộc cứng (không downtime, tránh long locks, tránh rewrite toàn bảng)
- Kết quả đầu ra: SQL cùng run plan bằng ngôn ngữ thường và rollback
Yêu cầu cả SQL lẫn run plan buộc model nghĩ tới thứ tự, rủi ro, và những gì cần kiểm tra trước khi phát hành.
Expand/contract bằng ngôn ngữ thường (và khi nào dùng)
Mẫu expand/contract thay đổi database PostgreSQL mà không làm vỡ app khi thay đổi đang diễn ra. Thay vì chuyển đổi một lần rủi ro, bạn làm cho database hỗ trợ cả hai dạng cũ và mới trong một khoảng thời gian.
Nghĩ đơn giản: thêm yếu tố mới an toàn (expand), chuyển dần traffic và dữ liệu, rồi chỉ khi chắc chắn, loại bỏ phần cũ (contract). Điều này đặc biệt hữu ích khi dùng trợ giúp AI vì nó buộc bạn lên kế hoạch cho phần giữa thường lộn xộn.
Bốn giai đoạn
Một flow thực tế trông như sau:
- Expand: thêm cột mới cho phép NULL hoặc bảng mới, thêm index nếu cần, và thêm constraint theo cách tránh blocking (ví dụ thêm constraint với NOT VALID khi thích hợp).
- Compatibility: cập nhật app để xử lý cả hai field. Có thể là dual-write (ghi cả hai) hoặc read-fallback (đọc mới, fallback về cũ).
- Backfill: sao chép dữ liệu cũ sang mới theo lô nhỏ, có checkpoint và cách resume.
- Contract: khi chắc mọi thứ dùng đường mới, siết ràng buộc (NOT NULL, validate constraint), rồi drop cột/bảng cũ.
Dùng pattern này khi người dùng có thể vẫn ở phiên bản app cũ trong khi database thay đổi. Bao gồm deployment đa instance, mobile app cập nhật chậm, hoặc bất kỳ release nào migration có thể kéo dài hàng phút hoặc hàng giờ.
Một chiến thuật hữu ích là lên kế hoạch cho hai release. Release 1 làm expand + compatibility để không gì vỡ nếu backfill chưa xong. Release 2 làm contract chỉ sau khi xác nhận code mới và dữ liệu mới đã sẵn sàng.
Mẫu prompt an toàn cho expand/contract migrations
Sao chép mẫu này và điền vào các ngoặc. Nó ép Claude Code tạo SQL bạn có thể chạy, các kiểm tra để chứng minh nó hoạt động, và kế hoạch rollback thực tế.
You are helping me plan a PostgreSQL expand-contract migration.
Context
- App: [what the feature does, who uses it]
- Database: PostgreSQL [version if known]
- Table sizes: [rough row counts], write rate: [low/medium/high]
- Zero/near-zero downtime required: [yes/no]
Goal
- Change: [describe the schema change]
- Current schema (relevant parts):
[paste CREATE TABLE or \d output]
- How the app will change (expand phase and contract phase):
- Expand: [new columns/indexes/triggers, dual-write, read preference]
- Contract: [when/how we stop writing old fields and remove them]
Hard safety requirements
- Prefer lock-safe operations. Avoid full table rewrites on large tables when possible.
- If any step can block writes, call it out explicitly and suggest alternatives.
- Use small, reversible steps. No “big bang” changes.
Deliverables
1) UP migration SQL (expand)
- Use clear comments.
- If you propose indexes, tell me if they should be created CONCURRENTLY.
- If you propose constraints, tell me whether to add them NOT VALID then VALIDATE.
2) Verification queries
- Queries to confirm the new schema exists.
- Queries to confirm data is being written to both old and new structures (if dual-write).
- Queries to estimate whether the change caused bloat/slow queries/locks.
3) Rollback plan (realistic)
- DOWN migration SQL (only if it is truly safe).
- If down is not safe, write a rollback runbook:
- how to stop the app change
- how to switch reads back
- what data might be lost or need re-backfill
4) Runbook notes
- Exact order of operations (including app deploy steps).
- What to monitor during the run (errors, latency, deadlocks, lock waits).
- “Stop/continue” checkpoints.
Output format
- Separate sections titled: UP.sql, VERIFY.sql, DOWN.sql (or ROLLBACK.md), RUNBOOK.md
Hai dòng thêm hữu dụng:
- Yêu cầu gắn nhãn mọi bước chặn ghi như
RISK: blocks writes, cùng đề xuất thời điểm chạy (off-peak vs anytime). - Ép sự thật về khóa: "Nếu bạn không chắc một statement có gây ACCESS EXCLUSIVE lock không, hãy nói rõ và đưa ra phương án an toàn hơn."
Các thao tác schema phổ biến và cách yêu cầu SQL an toàn hơn
Những thay đổi nhỏ vẫn có thể gây hại nếu chúng khóa lâu, rewrite bảng lớn, hoặc fail giữa chừng. Khi dùng Claude Code cho migrations, hãy yêu cầu SQL tránh rewrite và giữ app hoạt động trong khi database bắt kịp.
Thêm cột và default (không gây long locks)
Thêm cột nullable thường an toàn. Thêm cột với default không-null có thể rủi ro trên các phiên bản Postgres cũ vì nó có thể rewrite toàn bảng.
Cách an toàn hơn là thay đổi hai bước: thêm cột NULL không default, backfill theo lô, rồi đặt default cho hàng mới và thêm NOT NULL khi dữ liệu đã sạch.
Nếu bạn bắt buộc phải áp default ngay, yêu cầu giải thích về hành vi khóa cho phiên bản Postgres của bạn và phương án fallback nếu thời gian chạy lâu hơn dự kiến.
Indexes, FK, constraints, drops
Với index trên bảng lớn, yêu cầu CREATE INDEX CONCURRENTLY để đọc/ghi tiếp tục. Cũng nhắc rằng nó không thể chạy trong transaction block, nghĩa là công cụ migration của bạn cần bước không trong transaction.
Với foreign key, con đường an toàn thường là thêm constraint với NOT VALID trước, rồi validate sau. Điều này làm bước ban đầu nhanh hơn trong khi vẫn áp constraint cho các ghi mới.
Khi siết ràng buộc (NOT NULL, UNIQUE, CHECK), yêu cầu “clean first, enforce second.” Migration nên phát hiện hàng xấu, sửa chúng, rồi bật ràng buộc.
Nếu bạn cần checklist ngắn bỏ vào prompt, giữ nó súc tích:
- Bao gồm ghi chú về khóa và thời gian chạy ước tính.
- Dùng CONCURRENTLY cho index lớn và lưu ý giới hạn transaction.
- Ưu tiên NOT VALID rồi VALIDATE cho FK mới.
- Tách backfill khỏi việc áp NOT NULL/UNIQUE.
- Chỉ drop object sau một chu kỳ release đầy đủ và khi chắc chắn không ai đọc nó.
Gợi ý prompt cho backfill chậm, ổn định và có thể phục hồi
Backfill là nơi hầu hết đau đầu migration bộc lộ, chứ không phải ALTER TABLE. Prompt an toàn coi backfill như job được điều khiển: có thể đo lường, có thể restart, và nhẹ nhàng với production.
Bắt đầu với các kiểm tra chấp nhận dễ chạy và khó tranh cãi: số hàng dự kiến, mục tiêu tỉ lệ null, và vài spot-check (ví dụ so sánh giá trị cũ vs mới cho 20 ID ngẫu nhiên).
Rồi yêu cầu kế hoạch batching. Batching giữ khóa ngắn và giảm bất ngờ. Một yêu cầu tốt chỉ rõ:
- Cách batch (range PK hoặc windows theo thời gian như created_at)
- Kích thước batch mục tiêu (ví dụ 5.000 đến 50.000 hàng)
- Có ngủ giữa các batch trên bảng nóng hay không
- Mỗi batch nằm trong một transaction rõ ràng (không dùng một transaction khổng lồ)
Yêu cầu idempotency vì backfill có thể fail giữa chừng. SQL nên an toàn khi chạy lại mà không nhân đôi hay làm hỏng dữ liệu. Mẫu hay dùng là “update chỉ khi new_col IS NULL” hoặc quy tắc xác định đầu vào luôn cho cùng đầu ra.
Cũng mô tả cách app giữ đúng trong khi backfill chạy. Nếu ghi mới vẫn tới liên tục, bạn cần cầu nối: dual-write trong code, trigger tạm thời, hoặc read-fallback (đọc mới nếu có, nếu không đọc cũ). Nói rõ cách bạn có thể deploy an toàn.
Cuối cùng, xây khả năng pause và resume. Yêu cầu tracking tiến độ và checkpoint, như bảng nhỏ lưu last processed ID và truy vấn báo tiến độ (rows updated, last ID, thời gian bắt đầu).
Ví dụ: bạn thêm users.full_name từ first_name và last_name. Một backfill an toàn chỉ cập nhật những hàng full_name IS NULL, chạy theo range ID, ghi lại last updated ID, và giữ đăng ký mới nhất đúng nhờ dual-write cho tới khi chuyển đổi xong.
Cách yêu cầu kế hoạch rollback thật sự hữu dụng
Kế hoạch rollback không chỉ là “viết down migration.” Nó gồm hai vấn đề: undo thay đổi schema và xử lý dữ liệu thay đổi trong khi phiên bản mới hoạt động. Rollback schema thường khả thi. Rollback dữ liệu thường không, trừ khi bạn đã dự trù sẵn.
Hãy rõ ràng về ý nghĩa rollback cho thay đổi của bạn. Nếu bạn drop cột hoặc rewrite dữ liệu inplace, yêu cầu câu trả lời thực tế như: "Rollback phục hồi tương thích app, nhưng dữ liệu gốc không thể lấy lại nếu không có snapshot." Sự trung thực này giữ an toàn cho bạn.
Yêu cầu trigger rollback rõ ràng để không có tranh cãi khi sự cố. Ví dụ:
- Tỷ lệ lỗi hoặc latency vượt ngưỡng đã định trong 10 phút
- Một truy vấn quan trọng bị regress (ví dụ seq scan trên bảng nóng)
- Công việc backfill tụt hậu quá N giờ
- Kiểm tra dữ liệu thất bại (nulls, duplicate, missing rows)
- Một bước migration chặn ghi hơn X giây
Yêu cầu cả gói rollback, không chỉ SQL: DOWN SQL nếu an toàn, các bước app để giữ tương thích, và cách dừng background job.
Mẫu prompt gói thường đủ:
Produce a rollback plan for this migration.
Include: down migration SQL, app config/code switches needed for compatibility, and the exact order of steps.
State what can be rolled back (schema) vs what cannot (data) and what evidence we need before deciding.
Include rollback triggers with thresholds.
Trước khi phát hành, chụp một "safety snapshot" nhẹ để so sánh trước và sau:
- Số hàng cho các bảng bị ảnh hưởng (và các phân đoạn chính)
- Một vài truy vấn mẫu với kết quả mong đợi
- Các aggregate đơn giản (sum, min/max) cho cột được chạm tới
- Danh sách ID nhỏ để spot-check trước và sau
Cũng rõ ràng khi không nên rollback. Nếu bạn chỉ thêm cột nullable và app đang dual-write, sửa tiến lên (hotfix code, tạm dừng backfill, rồi resume) thường an toàn hơn revert và tạo thêm drift.
Các lỗi thường gặp khi dùng AI hỗ trợ migrations
AI viết SQL nhanh, nhưng nó không nhìn thấy database production của bạn. Hầu hết lỗi xảy ra khi prompt mơ hồ và model tự điền vào chỗ trống.
Bẫy phổ biến là bỏ qua schema hiện tại. Nếu bạn không dán định nghĩa bảng, index và constraint, SQL có thể nhắm vào cột không tồn tại hoặc bỏ sót một quy tắc duy nhất khiến backfill trở nên chậm và khóa nặng.
Một sai lầm khác là phát hàng expand, backfill và contract trong một deploy. Điều đó lấy mất cửa thoát. Nếu backfill chạy lâu hoặc lỗi giữa chừng, bạn kẹt với app mong trạng thái cuối cùng.
Vấn đề hay gặp nhất:
- Backfill không idempotent và không có tracking tiến độ
- Thêm NOT NULL, UNIQUE hoặc FK trước khi dọn dữ liệu và validate
- Transaction chạy lâu mà không có statement timeout hoặc lock timeout
- Không có truy vấn verify, nên lỗi bị che đi cho đến khi người dùng gặp phải
Ví dụ cụ thể: “đổi tên cột và cập nhật app.” Nếu plan sinh ra rename và backfill trong cùng một transaction, backfill chậm có thể giữ khóa và phá traffic. Một prompt an toàn ép dùng lô nhỏ, timeout rõ ràng và truy vấn verify trước khi loại bỏ đường cũ.
Những gì cần kiểm tra ở staging trước khi phát hành
Staging là nơi bạn tìm các vấn đề không hiện trên DB dev nhỏ: khóa lâu, null bất ngờ, index bị quên, và đường code bị bỏ sót.
Trước hết, kiểm tra schema khớp với plan sau migration: cột, kiểu, default, constraint và index. Quan sát nhanh không đủ—một index thiếu có thể biến backfill an toàn thành thảm họa.
Rồi chạy migration trên dataset thực tế. Lý tưởng là một bản sao production gần nhất với dữ liệu nhạy cảm đã mask. Nếu không làm được, ít nhất hãy mô phỏng volume production và các hotspot (bảng lớn, row rộng, bảng nhiều index). Ghi lại thời gian cho từng bước để biết mong đợi ở production.
Checklist staging ngắn:
- Schema khớp kế hoạch (cột, kiểu, constraint, index)
- Ghi lại thời gian chạy trên dữ liệu có qui mô thực tế
- Kiểm tra tương thích: app cũ với schema mới và app mới với schema cũ (khi plan nói nên vậy)
- Chạy verification queries: tỉ lệ null, số hàng, orphan checks cho FK mới, sample reads
- Theo dõi tín hiệu vận hành trong lúc chạy: locks, deadlocks, timeouts, slow queries
Cuối cùng, test luồng người dùng thật, không chỉ SQL. Tạo, cập nhật và đọc record liên quan thay đổi. Nếu dùng expand/contract, xác nhận cả hai schema hoạt động cho tới khi dọn dẹp cuối cùng.
Ví dụ thực tế: đổi cột mà không làm vỡ người dùng
Giả sử bạn có cột users.name lưu tên đầy đủ như "Ada Lovelace." Bạn muốn first_name và last_name, nhưng không thể làm vỡ signups, profile hay trang admin trong khi thay đổi triển khai.
Bắt đầu với bước expand an toàn ngay cả khi không có code thay đổi: thêm cột nullable, giữ cột cũ, và tránh khóa dài.
ALTER TABLE users ADD COLUMN first_name text;
ALTER TABLE users ADD COLUMN last_name text;
Rồi cập nhật hành vi app để hỗ trợ cả hai schema. Trong Release 1, app nên đọc từ cột mới khi có, fallback về name khi null, và ghi cả hai để dữ liệu mới nhất nhất quán.
Tiếp theo là backfill. Chạy job theo lô nhỏ, cập nhật một lượng hàng mỗi lần, ghi tiến độ và có thể pause an toàn. Ví dụ: update users where first_name is null theo thứ tự ID tăng dần, 1.000 hàng một lần, và log số hàng thay đổi.
Trước khi siết ràng buộc, validate ở staging:
- Signups mới điền
first_namevàlast_namevà vẫn setname - Người dùng cũ vẫn hiển thị đúng nếu chỉ có
name - Backfill có thể dừng và khởi động lại mà không nhân đôi công việc
- Không còn null bất ngờ sau khi backfill hoàn tất
- Truy vấn cơ bản trên
userskhông chậm rõ rệt
Release 2 chuyển sang chỉ đọc cột mới. Chỉ sau đó mới thêm constraint (ví dụ SET NOT NULL) và drop name, lý tưởng là trong deploy tách biệt muộn hơn.
Về rollback, giữ cho nó đơn giản. App tiếp tục đọc name trong quá trình chuyển đổi, và backfill có thể dừng. Nếu cần rollback Release 2, chuyển đọc về name và giữ các cột mới đến khi ổn định.
Bước tiếp theo: biến prompt của bạn thành thủ tục migration lặp lại được
Đối xử mỗi thay đổi như một runbook nhỏ. Mục tiêu không phải prompt hoàn hảo, mà là một quy trình ép ra các chi tiết đúng: schema, constraint, run plan và rollback.
Chuẩn hóa các thông tin bắt buộc trong mọi yêu cầu migration:
- Schema hiện tại và thay đổi chính xác (bảng, cột, index)
- Ràng buộc và thông tin traffic (kích thước bảng, write rate, downtime cho phép)
- Trình tự release (expand, deploy app, backfill, contract)
- Cách quan sát tiến độ (queries/metrics, runtime ước tính)
- Các bước rollback (cái nào revert trước, dữ liệu nào có thể để lại)
Quyết định ai sở hữu từng bước trước khi ai đó chạy SQL. Phân chia rõ ràng tránh "mọi người nghĩ người khác đã làm": dev sở hữu prompt và code migration, ops sở hữu thời điểm chạy production và monitoring, QA verify staging và edge case, và một người quyết go/no-go.
Nếu bạn xây app qua chat, mô tả trình tự trước khi sinh SQL có ích. Với teams dùng Koder.ai, Planning Mode là nơi hợp lý để viết sequence đó, và snapshots cộng rollback giảm diện hỏa khi xảy ra bất ngờ trong rollout.
Sau khi ship, lên lịch thực hiện cleanup (contract) ngay khi còn nhớ ngữ cảnh, để các cột cũ và code tương thích không tồn tại lửng lơ nhiều tháng.
Câu hỏi thường gặp
Why do PostgreSQL schema changes break production even when the SQL looks simple?
Một thay đổi schema trở nên rủi ro khi mã ứng dụng, trạng thái cơ sở dữ liệu và thời điểm triển khai không còn khớp nhau.
Các lỗi phổ biến:
- Mã ứng dụng cũ chạm tới cột/constraint mới và bị lỗi
- Một migration khóa mạnh lên bảng bận và các request bị timeout
- Một thay đổi “nhỏ” ghi đè hoặc xóa dữ liệu mà không ai để ý
- Công việc với index/constraint chạy lâu hơn dự kiến và gây chậm truy vấn
What’s the safest default way to change a schema without downtime?
Sử dụng phương pháp expand/contract an toàn:
- Expand: thêm cột/bảng/index có thể chấp nhận được (nullable, NOT VALID, v.v.)
- Compatibility: deploy mã ứng dụng có thể đọc/ghi cả hai cấu trúc
- Backfill: sao chép dữ liệu theo từng lô nhỏ với điểm kiểm soát
- Contract: siết chặt ràng buộc và xóa trường cũ chỉ sau khi xác nhận hoàn tất
Cách này giúp cả phiên bản ứng dụng cũ và mới cùng hoạt động trong quá trình rollout.
What extra risks do AI-generated migrations introduce?
Mô hình AI có thể tạo ra SQL hợp lệ nhưng không an toàn cho workload của bạn.
Rủi ro thường gặp liên quan tới AI:
- Dự đoán sai tên bảng/cột hoặc bỏ sót constraint quan trọng
- Đề xuất một migration “big bang” khiến bạn mất đường lui
- Bỏ qua hành vi khóa, giới hạn transaction và việc build index lâu
- Nói suông về rollback (đặc biệt khi dữ liệu bị biến đổi hoặc bị xóa)
Xử lý đầu ra của AI như bản nháp: luôn yêu cầu kế hoạch chạy, kiểm tra và bước rollback.
What should I paste into my prompt so Claude Code doesn’t guess?
Dán vào prompt chỉ những sự thật migration cần:
- Các đoạn
CREATE TABLEliên quan (cộng với index, FK, UNIQUE/CHECK, trigger) - Phiên bản Postgres và cách chạy migration (one transaction hay nhiều bước)
- Qui mô: số hàng, kích thước bảng, tốc độ ghi, peak traffic
- Cách ứng dụng dùng dữ liệu (read/write/job quan trọng)
- Ràng buộc cứng (không downtime, tránh rewrite toàn bảng, giới hạn khóa)
- Kết quả yêu cầu: UP SQL + verification queries + rollback plan + runbook
Điều này ngăn model đoán mò và ép mô tả thứ tự bước thực hiện.
Should I combine schema changes and backfills in one migration?
Quy tắc mặc định: tách chúng ra.
Một chuỗi thực tế:
- Migration 1: mở schema (thêm cột/bảng, có thể NOT VALID)
- App deploy: mã tương thích (read-fallback hoặc dual-write)
- Backfill job: cập nhật theo lô với tracking tiến độ
- Migration 2: contract (validate constraint, set NOT NULL, drop column)
Gộp tất cả làm một sẽ khiến lỗi khó chẩn đoán và quay lui.
How do I add a new column with a default without causing long locks?
Ưu tiên theo mẫu:
ADD COLUMN ... NULLkhông default (nhanh)- Backfill theo lô
- Đặt default cho các hàng mới
- Thêm
NOT NULLchỉ sau khi xác minh
Thêm default không-null ngay lập tức có thể gây rewrite toàn bộ bảng trên một số phiên bản Postgres. Nếu cần default ngay, yêu cầu phần giải thích về hành vi khóa và phương án dự phòng.
When should I use CREATE INDEX CONCURRENTLY, and what’s the catch?
Hãy yêu cầu:
CREATE INDEX CONCURRENTLYcho bảng lớn/nóng- Lưu ý rằng nó không chạy trong một transaction block (tooling của bạn phải hỗ trợ)
- Thời gian chạy ước tính và các chỉ số cần theo dõi (lock waits, query latency)
Trong bước verify, so sánh EXPLAIN trước/sau ở staging để đảm bảo index được dùng.
What’s the safest way to add a foreign key on a large table?
Dùng NOT VALID trước, rồi VALIDATE sau:
- Thêm FK với
NOT VALIDđể bước ban đầu ít gây gián đoạn - Chạy
VALIDATE CONSTRAINTriêng khi bạn có thể giám sát nó
Cách này vẫn áp dụng FK cho các ghi mới, đồng thời bạn kiểm soát khi validation tốn tài nguyên được thực hiện.
How do I prompt for a backfill that won’t melt production and can resume?
Một backfill tốt là theo lô, idempotent và có thể resume.
Yêu cầu thực tế:
- Batch theo PK ranges hoặc windows thời gian
- Chỉ update những hàng còn thiếu (ví dụ
WHERE new_col IS NULL) - Giữ mỗi batch trong transaction ngắn; có thể sleep giữa các batch
- Lưu progress (last processed ID, rows updated, start time)
- Đảm bảo app vẫn đúng trong quá trình backfill (dual-write, trigger, hoặc read-fallback)
Thiết kế này giúp backfill chịu được traffic thực tế.
What does a realistic rollback plan look like for schema changes?
Mục tiêu rollback mặc định: phục hồi tính tương thích của app nhanh, ngay cả khi dữ liệu không hoàn toàn khôi phục.
Một kế hoạch rollback thực tế gồm:
- Xác định xem DOWN SQL có thực sự an toàn không; nếu không, viết runbook
- Trình tự rõ ràng: dừng/pause backfill, deploy mã app rollback, rồi các bước schema
- Các trigger rollback rõ ràng (tỷ lệ lỗi, latency, lock waits, kiểm tra dữ liệu thất bại)
- Ghi rõ cái gì có thể rollback (schema) và cái gì không (dữ liệu)
Thường cách an toàn nhất là chuyển đọc trở lại trường cũ trong khi giữ các cột mới nguyên vẹn.