TopDev AI Robot TopDev
#Backend & Microservices#Cơ sở dữ liệu & Tối ưu#DevOps & Cloud

Chiến lược Zero-Downtime Migration trên PostgreSQL với CREATE INDEX CONCURRENTLY

Thu Trang (Backend Engineer)
📖 2 phút đọc 💬 1 phản hồi
⚡ Tóm tắt 30 giây bởi TopDev AI
AI Overview

Nỗi sợ mỗi khi chạy lệnh Database Migration trên Production Đã bao nhiêu lần team bạn phải thức dậy lúc 2h sáng chỉ để chạy một lệnh thêm cột hoặc tạo index mới? Nếu chạy CREATE INDEX trên bảng có hà…

☰ Mục lục bài viết (5 phần) Mở / Đóng mục lục

Nỗi sợ mỗi khi chạy lệnh Database Migration trên Production#

Đã bao nhiêu lần team bạn phải thức dậy lúc 2h sáng chỉ để chạy một lệnh thêm cột hoặc tạo index mới? Nếu chạy CREATE INDEX trên bảng có hàng chục triệu dòng theo cách thông thường, PostgreSQL sẽ đặt một khóa độc quyền (SHARE LOCK):

  • Mọi lệnh INSERT, UPDATE, DELETE từ người dùng đều bị chặn lại và xếp hàng chờ.
  • Connection pool bị dồn ứ, dẫn tới sập ứng dụng (Downtime).

Dưới đây là các kỹ thuật thực chiến để migration database mượt mà 0 giây gián đoạn.

1. Tạo Index không chặn ghi với CONCURRENTLY#

SQL
-- ĐÚNG: Chạy song song không khóa bảng
CREATE INDEX CONCURRENTLY idx_users_email_active ON users (email) WHERE is_active = true;
  • Lưu ý quan trọng: Lệnh CONCURRENTLY không thể chạy bên trong một Transaction block (BEGIN ... COMMIT). Nếu công cụ migration của bạn (Prisma, TypeORM, Knex) tự động bọc câu lệnh trong transaction, bạn phải tắt cờ transaction cho file migration đó.
  • Nếu quá trình tạo bị lỗi (ví dụ rớt mạng), index sẽ rơi vào trạng thái INVALID. Bạn cần drop index và chạy lại.

2. Thêm cột mới có giá trị mặc định (DEFAULT) an toàn#

  • Từ PostgreSQL 11 trở lên: Lệnh ALTER TABLE ... ADD COLUMN ... DEFAULT 'abc' chỉ cập nhật metadata trong catalog của Postgres, diễn ra trong vài mili-giây và không phải viết lại toàn bộ bảng.
  • Thêm cột NOT NULL: Nên thêm cột NULL trước, cập nhật dữ liệu theo lô nhỏ (batching), sau đó mới thêm ràng buộc CHECK (...) NOT VALID rồi mới VALIDATE CONSTRAINT.

3. Đặt Timeout an toàn cho lệnh Lock#

Để tránh việc migration đứng chờ một transaction khác quá lâu làm tắc nghẽn cả hệ thống:

SQL
SET lock_timeout = '3s';
ALTER TABLE orders ADD COLUMN notes TEXT;

Nếu sau 3 giây không lấy được lock, lệnh sẽ tự hủy an toàn thay vì làm nghẽn hàng ngợi của client.

Góc thảo luận#

Team bạn đang dùng công cụ migration nào (Flyway, Liquibase, Prisma, golang-migrate)? Quy trình deploy migration lên production của anh em diễn ra thế nào?


Xem thêm nội dung liên quan:

Chia sẻ thảo luận này:

Thảo luận

1 phản hồi

Ý kiến từ cộng đồng kỹ sư TopDev
💬

Tham gia thảo luận

Cộng đồng mở · Đăng nhập 1-chạm qua Google
  1. Việt Anh (Cloud Architect)
    #1

    Mẹo SET lock_timeout = '3s' trước khi chạy DDL là cực kỳ quý giá! Trước đây bên mình từng bị dính quả một transaction đọc chậm giữ lock, thế là lệnh ALTER TABLE đứng chờ kéo theo cả ngàn request sau bị chết chùm.

Bài liên quan trong #Backend & Microservices

1
TopDev AI Companion
AI
✓ Đã sao chép link