1. 13:19 24/08/2026
Thay đổi cấu trúc cơ sở dữ liệu là việc khó tránh trong quá trình phát triển web/app, nhưng cũng là nguồn gây lỗi phổ biến khi triển khai. Một migration tưởng như đơn giản, chẳng hạn đổi tên cột hoặc thêm trường bắt buộc, có thể làm phiên bản ứng dụng cũ không đọc được dữ liệu, khiến truy vấn chậm hoặc làm gián đoạn người dùng đang hoạt động.
Cách tiếp cận an toàn thường là chiến lược expand-and-contract: mở rộng cấu trúc trước, chuyển dần cách sử dụng, rồi mới thu gọn phần cũ.
1. Mở rộng schema trước
Nếu cần đổi cột customer_name thành full_name trong bảng users, đừng xóa ngay cột cũ. Hãy thêm full_name cho phép giá trị rỗng, sau đó phát hành phiên bản ứng dụng có khả năng ghi cả hai cột. Ở bước này, phiên bản cũ vẫn có thể đọc customer_name nên việc triển khai theo từng máy chủ ít rủi ro hơn.
Với trường mới hoặc index mới, cần cân nhắc tác động lên bảng lớn. Một số hệ quản trị có cách tạo index không khóa toàn bộ bảng, nhưng cách thực hiện phụ thuộc vào công nghệ và cấu hình cụ thể. Hãy kiểm tra tài liệu của hệ quản trị đang dùng và thử trên dữ liệu có kích thước gần với môi trường thật.
2. Đồng bộ và chuyển dữ liệu
Sau khi schema đã sẵn sàng, chạy tác vụ backfill để sao chép dữ liệu cũ sang trường mới theo từng lô nhỏ. Không nên cập nhật hàng triệu bản ghi trong một giao dịch duy nhất nếu việc đó có thể giữ khóa quá lâu hoặc làm đầy log giao dịch. Tác vụ cần có khả năng tiếp tục sau khi lỗi, ghi nhận tiến độ và giới hạn tốc độ để không tranh chấp tài nguyên với lưu lượng thực tế.
Trong thời gian chuyển tiếp, nên xác định nguồn dữ liệu chính. Nếu ứng dụng ghi vào cả hai trường, cần xử lý trường hợp một thao tác thành công còn thao tác kia thất bại. Có thể dùng transaction khi hai cột nằm cùng cơ sở dữ liệu, hoặc xây dựng cơ chế đối soát và sửa lệch nếu dữ liệu được cập nhật qua các thành phần khác nhau.
3. Chuyển sang đọc dữ liệu mới
Khi đã backfill xong, phát hành phiên bản đọc full_name nhưng vẫn có phương án dự phòng sang customer_name trong một khoảng thời gian. Theo dõi log, tỷ lệ giá trị rỗng và các truy vấn lỗi trước khi quyết định loại bỏ cách đọc cũ. Nếu hệ thống có nhiều service, cần kiểm tra tất cả consumer, job nền và công cụ quản trị chứ không chỉ ứng dụng chính.
4. Thu gọn sau khi xác nhận
Chỉ xóa cột cũ khi không còn phiên bản ứng dụng hoặc tác vụ nào sử dụng nó. Tốt hơn hết là tách thao tác xóa thành một migration riêng, triển khai sau một khoảng thời gian quan sát. Việc tách bước giúp rollback ứng dụng dễ hơn, dù cần nhớ rằng rollback mã nguồn không tự động khôi phục dữ liệu đã bị xóa.
Một checklist thực tế trước khi chạy migration gồm:
- Xác định bảng, index, khóa ngoại và các service có liên quan.
- Kiểm thử migration trên bản sao dữ liệu có kích thước tương đương.
- Đo thời gian chạy, mức sử dụng CPU, bộ nhớ, I/O và tác động đến truy vấn.
- Chuẩn bị phương án dừng hoặc tiếp tục migration khi có lỗi.
- Kiểm tra backup và khả năng khôi phục, không chỉ kiểm tra việc backup đã được tạo.
- Ghi rõ thứ tự triển khai giữa schema, backend, frontend và job nền.
Migration tốt không chỉ là một file lệnh chạy thành công. Đó là một chuỗi thay đổi có thể quan sát, tiếp tục an toàn và hạn chế phụ thuộc vào thời điểm triển khai. Khi thiết kế migration theo từng bước nhỏ, đội phát triển giảm được thời gian gián đoạn và có thêm lựa chọn xử lý nếu dữ liệu hoặc lưu lượng thực tế khác với dự đoán.