~/VibeHandbook
PDF miễn phí

Chương 14 · 03

Cơ bản về thiết kế Schema

Một schema là bản thiết kế cho dữ liệu của bạn: những bảng nào tồn tại, chúng có những cột nào, và chúng liên hệ với nhau ra sao. Thiết kế schema tốt phần lớn là lẽ thường cộng với vài thói quen.

  • Một bảng cho mỗi "thứ." Người dùng, bài viết, đơn hàng — mỗi thứ có bảng riêng.
  • Mỗi dòng cần một ID duy nhất (khóa chính — primary key).
  • Liên kết các bảng bằng khóa ngoại (foreign key), chứ không phải bằng cách sao chép dữ liệu qua lại.
  • Chọn kiểu dữ liệu trung thực. Tiền là decimal, không phải float. Ngày tháng là timestamp, không phải văn bản.
  • Đừng nhân đôi dữ liệu. Nếu email của người dùng nằm ở năm bảng khác nhau, cuối cùng bạn sẽ có năm email khác nhau.

Đây là một schema đơn giản cho một blog, kiểu mà AI sẽ tạo cho bạn:

CREATE TABLE users (
    id          UUID PRIMARY KEY DEFAULT gen_random_uuid(),
    email       TEXT NOT NULL UNIQUE,
    created_at  TIMESTAMPTZ NOT NULL DEFAULT now()
);

CREATE TABLE posts (
    id          UUID PRIMARY KEY DEFAULT gen_random_uuid(),
    author_id   UUID NOT NULL REFERENCES users(id),
    title       TEXT NOT NULL,
    body        TEXT NOT NULL,
    published   BOOLEAN NOT NULL DEFAULT false,
    created_at  TIMESTAMPTZ NOT NULL DEFAULT now()
);

CREATE INDEX idx_posts_author ON posts(author_id);

Dòng author_id ... REFERENCES users(id) đó chính là khóa ngoại. Nó nối mỗi bài viết trở lại đúng một người dùng có thật, vì vậy bản thân cơ sở dữ liệu sẽ từ chối lưu một bài viết không có tác giả hợp lệ:

   users                          posts
   ┌─────────────┐                ┌─────────────┐
   │ id  (PK) ◀──┼────────────────┤ author_id   │  (FK → users.id)
   │ email       │   one user      │ id  (PK)    │
   │ created_at  │   has many      │ title       │
   └─────────────┘   posts         │ body        │
                                   │ published   │
        1  ────────────────────▶  *└─────────────┘
       (one)                    (many)

Hãy chú ý đến REFERENCES (một khóa ngoại gắn một bài viết với một người dùng có thật) cùng các ràng buộc NOT NULLUNIQUE. Đây là những rào chắn mà cơ sở dữ liệu tự thực thi giúp bạn, để dữ liệu xấu không thể lọt vào ngay cả khi code của bạn có lỗi.

Một ràng buộc đáng cân nhắc thêm một cách chủ động là điều gì xảy ra khi bản ghi cha biến mất. Theo mặc định, việc xóa một người dùng mà các bài viết của họ vẫn còn tham chiếu tới sẽ thất bại — điều này thường là điều bạn muốn. Nhưng bạn có thể chỉ định rõ ràng: REFERENCES users(id) ON DELETE CASCADE sẽ xóa luôn các bài viết, trong khi ON DELETE RESTRICT sẽ chặn việc xóa. Chủ động lựa chọn tốt hơn nhiều so với việc phát hiện ra hành vi mặc định một cách đau đớn khi đã lên production. Cùng bản năng "để cơ sở dữ liệu bảo vệ bạn" này cũng áp dụng cho ràng buộc CHECK (CHECK (price >= 0)) — nó từ chối dữ liệu vô lý ngay tại nguồn thay vì tin tưởng mọi luồng code đều xác thực đúng.

Muốn bản ngoại tuyến?

Tải trọn cuốn sách dưới dạng PDF hoặc EPUB — miễn phí.