7 phút

Ràng buộc PostgreSQL trước: chặn sớm lỗi biên do AI

Phát hành ứng dụng do AI tạo an toàn hơn bằng cách đặt ràng buộc PostgreSQL (NOT NULL, CHECK, UNIQUE, FOREIGN KEY) làm hàng rào trước khi code và test.

Ràng buộc PostgreSQL trước: chặn sớm lỗi biên do AI

Tại sao mã do AI viết vẫn vỡ trên dữ liệu lộn xộn

Mã do AI viết thường trông đúng vì nó xử lý đường đi đẹp (happy path). Ứng dụng thực tế thất bại ở phần giữa lộn xộn: một form gửi chuỗi rỗng thay vì null, một job nền thử lại và tạo cùng một bản ghi hai lần, hoặc một thao tác xóa gỡ hàng cha và để lại con mồ côi. Đây không phải là lỗi kỳ lạ. Chúng xuất hiện dưới dạng trường bắt buộc trống, giá trị “unique” trùng lặp, và dòng mồ côi trỏ đến chỗ không tồn tại.

Chúng cũng lọt qua code review và test cơ bản vì lý do đơn giản: người review đọc ý định, không phải mọi trường hợp biên. Test thường bao phủ vài ví dụ điển hình, không phải hàng tuần hành vi người dùng thực, import từ CSV, retry do mạng, hay các request đồng thời. Nếu một assistant sinh mã, nó có thể bỏ sót những kiểm tra nhỏ nhưng quan trọng như cắt khoảng trắng, xác thực phạm vi, hoặc phòng tránh điều kiện đua.

“Ràng buộc trước, mã sau” nghĩa là bạn đặt các quy tắc không thể thương lượng trong cơ sở dữ liệu để dữ liệu xấu không thể lưu lại, dù đường viết dữ liệu đến từ đâu. Ứng dụng nên vẫn xác thực đầu vào để trả lỗi rõ ràng, nhưng cơ sở dữ liệu thực thi sự thật. Đó là nơi PostgreSQL constraints tỏa sáng: chúng bảo vệ bạn khỏi cả nhóm sai sót.

Một ví dụ nhanh: tưởng tượng một CRM nhỏ. Một script import do AI sinh tạo liên hệ. Một hàng có email là "" (rỗng), hai hàng lặp cùng email với chữ viết hoa khác nhau, và một liên hệ tham chiếu account_id không tồn tại vì tài khoản đã bị xóa ở quá trình khác. Nếu không có ràng buộc, tất cả những điều đó có thể vào production và phá báo cáo sau này.

Với quy tắc đúng, các ghi đó bị từ chối ngay lập tức, gần nguồn gây lỗi. Trường bắt buộc không thể thiếu, bản sao không thể lẻn vào khi retry, quan hệ không thể trỏ tới bản ghi đã bị xóa hoặc không tồn tại, và giá trị không thể nằm ngoài phạm vi cho phép.

Ràng buộc không ngăn mọi lỗi. Chúng không sửa giao diện gây nhầm lẫn, tính toán chiết khấu sai, hay câu truy vấn chậm. Nhưng chúng ngăn dữ liệu xấu tích tụ âm thầm, thường là lúc các “lỗi biên do AI” trở nên tốn kém.

Tại sao cơ sở dữ liệu nên là hàng rào cuối cùng

Ứng dụng của bạn hiếm khi chỉ là một codebase giao tiếp với một người dùng. Một sản phẩm điển hình có web UI, app di động, màn hình admin, job nền, import CSV, và đôi khi tích hợp bên thứ ba. Mỗi đường đi đều có thể tạo hoặc thay đổi dữ liệu. Nếu mọi đường phải nhớ cùng một quy tắc, sẽ có đường quên.

Cơ sở dữ liệu là nơi chung mà tất cả chia sẻ. Khi bạn coi nó như người gác cổng cuối cùng, quy tắc áp dụng cho mọi thứ tự động. Các constraint của PostgreSQL biến “chúng tôi giả định điều này luôn đúng” thành “điều này phải đúng, nếu không ghi bị từ chối.”

Mã do AI sinh làm chuyện này càng quan trọng hơn. Một model có thể thêm xác thực form trong React nhưng bỏ sót góc nhỏ trong job nền. Hoặc nó xử lý dữ liệu happy-path tốt, rồi vỡ khi khách hàng thực nhập thứ bất ngờ. Ràng buộc bắt lỗi đúng lúc dữ liệu xấu cố vào, không phải vài tuần sau khi bạn gỡ lỗi các báo cáo kỳ lạ.

Khi bạn bỏ qua ràng buộc, dữ liệu xấu thường im lặng. Lưu thành công, app tiếp tục, và vấn đề xuất hiện sau này như ticket hỗ trợ, sai lệch tính phí, hoặc dashboard không ai tin. Dọn dẹp tốn kém vì bạn sửa lịch sử, không phải một request.

Dữ liệu xấu thường lẻn vào qua các tình huống hàng ngày: phiên bản client mới gửi trường là rỗng thay vì không tồn tại, retry tạo trùng, sửa admin bỏ qua kiểm tra UI, file import có định dạng không nhất quán, hoặc hai người cùng cập nhật bản ghi liên quan cùng lúc.

Một mô hình tư duy hữu dụng: chỉ chấp nhận dữ liệu nếu nó hợp lệ tại ranh giới. Trong thực tế, ranh giới đó nên bao gồm cơ sở dữ liệu, vì cơ sở dữ liệu thấy mọi ghi.

NOT NULL: ngăn dữ liệu bắt buộc bị thiếu sớm

NOT NULL là ràng buộc đơn giản nhất của PostgreSQL, và nó ngăn một lớp lỗi đáng ngạc nhiên. Nếu một giá trị phải tồn tại để hàng có ý nghĩa, hãy để cơ sở dữ liệu thực thi điều đó.

NOT NULL thường đúng cho định danh, tên bắt buộc, và timestamps. Nếu bạn không thể tạo bản ghi hợp lệ mà thiếu nó, đừng cho phép nó rỗng. Trong CRM nhỏ, một lead không có owner hoặc created time không phải là “lead một phần”. Đó là dữ liệu hỏng sẽ gây hành vi kỳ lạ về sau.

NULL len lỏi thường hơn với mã do AI sinh vì dễ tạo các đường “tùy chọn” mà không để ý. Một trường form có thể tùy chọn trong UI, API chấp nhận key thiếu, và một nhánh của hàm tạo có thể bỏ qua gán giá trị. Mọi thứ vẫn biên dịch và test happy-path pass. Rồi người dùng import CSV với ô trống, hoặc client di động gửi payload khác, và NULL vào DB.

Một pattern hữu ích là kết hợp NOT NULL với default hợp lý cho các trường hệ thống quản lý:

  • created_at TIMESTAMP NOT NULL DEFAULT now()
  • status TEXT NOT NULL DEFAULT 'new'
  • is_active BOOLEAN NOT NULL DEFAULT true

Default không luôn là chiến thắng. Đừng đặt mặc định cho các trường do người dùng cung cấp như email hoặc company_name chỉ để thỏa NOT NULL. Chuỗi rỗng không “hợp lệ” hơn NULL; nó chỉ che giấu vấn đề.

Khi băn khoăn, quyết định giá trị đó thật sự là “không biết” hay nó biểu thị một trạng thái khác. Nếu “chưa cung cấp” có ý nghĩa, hãy cân nhắc một cột trạng thái riêng thay vì cho phép NULL khắp nơi. Ví dụ: để phone nullable, nhưng thêm phone_status như missing, requested, hoặc verified. Điều này giữ ý nghĩa nhất quán trong code.

CHECK: mã hóa luật nghiệp vụ gần dữ liệu

Một CHECK constraint là lời hứa bảng của bạn đưa ra: mỗi hàng phải thỏa một quy tắc, mọi lúc. Đây là một trong những cách dễ nhất để ngăn các trường hợp biên tạo ra các bản ghi trông hợp lý ở mã nhưng vô nghĩa trong thực tế.

CHECK phù hợp nhất cho các quy tắc chỉ phụ thuộc giá trị trong cùng một hàng: phạm vi số, giá trị cho phép, và quan hệ đơn giản giữa các cột.

-- 1) Totals should never be negative
ALTER TABLE invoices
  ADD CONSTRAINT invoices_total_nonnegative
  CHECK (total_cents >= 0);

-- 2) Enum-like allowed values without adding a custom type
ALTER TABLE tickets
  ADD CONSTRAINT tickets_status_allowed
  CHECK (status IN ('new', 'open', 'waiting', 'closed'));

-- 3) Date order rules
ALTER TABLE subscriptions
  ADD CONSTRAINT subscriptions_date_order
  CHECK (end_date IS NULL OR end_date >= start_date);

Một CHECK tốt dễ đọc thoáng qua. Hãy coi nó như tài liệu cho dữ liệu của bạn. Ưu tiên biểu thức ngắn, tên constraint rõ ràng, và mẫu dự đoán được.

CHECK không phải công cụ cho mọi thứ. Nếu quy tắc cần tra cứu hàng khác, tổng hợp, hoặc so sánh xuyên bảng (ví dụ “một account không được vượt giới hạn gói”), giữ logic đó ở mã ứng dụng, trigger, hoặc job nền có kiểm soát.

UNIQUE: ngăn trùng mà bạn sẽ hối hận sau này

Chia sẻ quy tắc dữ liệu
Đồng nhất lập trình viên và thành viên không kỹ thuật về những gì phải luôn đúng.

UNIQUE đơn giản: cơ sở dữ liệu từ chối lưu hai hàng có cùng giá trị trong cột bị ràng buộc (hoặc cùng tổ hợp cột). Điều này xóa cả một lớp lỗi khi đường tạo chạy hai lần, retry xảy ra, hoặc hai người dùng gửi cùng lúc.

UNIQUE đảm bảo không trùng cho chính xác giá trị bạn định nghĩa. Nó không đảm bảo giá trị có tồn tại (NOT NULL), tuân theo định dạng (CHECK), hay khái niệm bằng nhau của bạn (chữ hoa, khoảng trắng, dấu câu) trừ khi bạn định nghĩa nó.

Những chỗ thường muốn UNIQUE gồm email trên bảng user, external_id từ hệ thống khác, hoặc tên phải duy nhất trong một account như (account_id, name).

Một lưu ý: NULL và UNIQUE. Trong PostgreSQL, NULL được coi là “không biết”, nên nhiều NULL được phép dưới UNIQUE. Nếu bạn muốn “giá trị phải tồn tại và phải duy nhất”, kết hợp UNIQUE với NOT NULL.

Một pattern thực tế cho định danh người dùng là duy nhất không phân biệt hoa thường. Mọi người sẽ gõ “[email protected]” rồi sau đó “[email protected]” và mong là giống nhau.

-- Case-insensitive unique email
CREATE UNIQUE INDEX users_email_unique_ci
ON users (lower(email));

-- Unique contact name per account
ALTER TABLE contacts
ADD CONSTRAINT contacts_account_name_unique UNIQUE (account_id, name);

Xác định “trùng” nghĩa là gì với người dùng của bạn (hoa thường, khoảng trắng, theo tài khoản hay toàn cục), rồi mã hóa nó một lần để mọi đường viết theo cùng một quy tắc.

FOREIGN KEY: giữ cho quan hệ nhất quán

FOREIGN KEY nói rằng “hàng này phải trỏ tới một hàng thực ở chỗ kia.” Nếu không có nó, mã có thể âm thầm tạo các bản ghi mồ côi trông hợp lệ một mình nhưng phá ứng dụng sau này. Ví dụ: một note tham chiếu customer đã bị xóa, hoặc một invoice trỏ tới user_id chưa từng tồn tại.

Foreign key quan trọng nhất khi hai hành động xảy ra gần nhau: xóa và tạo, retry sau timeout, hoặc job nền chạy với dữ liệu cũ. Cơ sở dữ liệu giỏi hơn ở việc đảm bảo nhất quán hơn là mọi đường viết phải nhớ kiểm tra.

Chọn hành vi ON DELETE phù hợp

Tùy chọn ON DELETE nên khớp với ý nghĩa thực tế của quan hệ. Hỏi: “Nếu hàng cha biến mất, con có nên tồn tại không?”

  • RESTRICT (hoặc NO ACTION): chặn xóa cha nếu còn con.
  • CASCADE: xóa cha sẽ xóa luôn con.
  • SET NULL: giữ con nhưng xóa liên kết.

Cẩn thận với CASCADE. Nó có thể đúng, nhưng cũng có thể xóa nhiều hơn bạn mong khi một bug hoặc hành động admin xóa cha.

Multi-tenant schemas: mô tả quyền sở hữu rõ ràng

Trong app đa tenant, foreign key không chỉ về tính đúng. Chúng còn ngăn rò rỉ giữa các account. Một pattern phổ biến là thêm account_id trên mọi bảng thuộc sở hữu tenant và nối quan hệ qua nó.

CREATE TABLE contacts (
  account_id bigint NOT NULL,
  id bigint GENERATED ALWAYS AS IDENTITY,
  PRIMARY KEY (account_id, id)
);

CREATE TABLE notes (
  account_id bigint NOT NULL,
  id bigint GENERATED ALWAYS AS IDENTITY,
  contact_id bigint NOT NULL,
  body text NOT NULL,
  PRIMARY KEY (account_id, id),
  FOREIGN KEY (account_id, contact_id)
    REFERENCES contacts (account_id, id)
    ON DELETE RESTRICT
);

Điều này thực thi “ai sở hữu cái gì” ngay trong schema: một note không thể trỏ tới contact của account khác, ngay cả khi mã app (hoặc một truy vấn do LLM sinh) cố làm vậy.

Từng bước: thêm ràng buộc mà không làm vỡ production

Xây ứng dụng với ràng buộc
Xây dựng với quy tắc Postgres trong đầu và để cơ sở dữ liệu ngăn dữ liệu xấu sớm.

Bắt đầu bằng cách viết một danh sách ngắn các bất biến: các sự thật phải luôn đúng. Giữ chúng đơn giản. “Mỗi contact cần một email.” “Một status phải là một trong vài giá trị cho phép.” “Một invoice phải thuộc về một customer thực.” Đây là các quy tắc bạn muốn DB thực thi mỗi lần.

Triển khai thay đổi thành các migration nhỏ để production không bị bất ngờ:

  • Thêm cột hoặc quy tắc mới theo cách không phá vỡ trước.
  • Backfill các hàng hiện có theo lô.
  • Dọn dữ liệu xấu (gộp trùng, sửa giá trị không hợp lệ) hoặc cách ly để review.
  • Thi hành quy tắc (NOT NULL, UNIQUE, CHECK, FOREIGN KEY).
  • Thắt chặt hành vi app để lỗi được xử lý rõ ràng.

Phần lộn xộn là dữ liệu xấu hiện có. Lên kế hoạch cho nó. Với trùng lặp, chọn một hàng giữ, gộp phần còn lại, và giữ một ghi chú audit nhỏ. Với trường bắt buộc thiếu, chọn default an toàn chỉ khi thật sự an toàn; nếu không, cách ly. Với quan hệ hỏng, gán lại các hàng con về cha đúng hoặc xóa các hàng xấu.

Sau mỗi migration, kiểm tra với vài ghi mà lẽ ra phải fail: insert hàng thiếu giá trị bắt buộc, insert khóa trùng, insert giá trị ngoài phạm vi, và tham chiếu cha không tồn tại. Ghi bị từ chối là tín hiệu hữu ích. Chúng cho bạn thấy chỗ mà app âm thầm dựa vào hành vi “nỗ lực tốt nhất”.

Một ví dụ thực tế: CRM nhỏ giữ sạch dữ liệu

Hình dung một CRM nhỏ: accounts (mỗi khách hàng của SaaS), companies họ làm việc, contacts tại các công ty đó, và deals liên kết với company.

Đây chính xác là loại app người ta thường sinh nhanh bằng công cụ chat. Nó trông ổn trong demo, nhưng dữ liệu thực trở nên lộn xộn nhanh. Hai lỗi xuất hiện sớm: contact trùng lặp (cùng email nhập hai lần theo cách hơi khác), và deals được tạo mà không có company vì một đường viết quên set company_id. Một lỗi kinh điển khác là giá trị deal âm sau khi refactor hoặc lỗi parse.

Cách sửa không phải thêm hàng loạt if. Là vài ràng buộc chọn lọc khiến dữ liệu xấu không thể lưu.

Các ràng buộc giữ CRM sạch

-- Contacts: prevent duplicates per account
ALTER TABLE contacts
  ADD CONSTRAINT contacts_account_email_uniq UNIQUE (account_id, email);

-- Deals: require a company and keep the relationship valid
ALTER TABLE deals
  ALTER COLUMN company_id SET NOT NULL,
  ADD CONSTRAINT deals_company_fk
    FOREIGN KEY (company_id) REFERENCES companies(id);

-- Deals: deal value cannot be negative
ALTER TABLE deals
  ADD CONSTRAINT deals_value_nonneg CHECK (deal_value >= 0);

-- A few obvious required fields
ALTER TABLE companies
  ALTER COLUMN name SET NOT NULL;
ALTER TABLE contacts
  ALTER COLUMN email SET NOT NULL;

Đây không phải chuyện khắt khe cho vui. Bạn biến kỳ vọng mơ hồ thành quy tắc mà DB có thể thi hành mọi lúc, dù phần nào của app ghi dữ liệu.

App thay đổi như thế nào sau khi đó

Khi các ràng buộc này có hiệu lực, app trở nên đơn giản hơn. Bạn có thể loại bỏ nhiều kiểm tra phòng thủ từng phần cố gắng phát hiện trùng sau khi đã xảy ra. Lỗi trở nên rõ ràng và có thể hành động (ví dụ “email đã tồn tại cho account này” thay vì hành vi kỳ lạ ở downstream). Khi một route API sinh ra quên trường hoặc xử lý sai giá trị, ghi bị từ chối ngay thay vì vô âm thầm làm hỏng DB.

Sai lầm phổ biến khiến ràng buộc trở nên khó chịu

Từ schema tới triển khai
Đẩy nhanh bằng cách triển khai app khi ràng buộc và xác thực đã khớp nhau.

Ràng buộc phát huy tốt nhất khi chúng khớp với cách doanh nghiệp thực sự hoạt động. Hầu hết khó chịu đến từ việc thêm quy tắc có vẻ “an toàn” lúc đó nhưng thành bất ngờ sau này.

Bẫy phổ biến là dùng ON DELETE CASCADE khắp nơi. Trông gọn gàng cho tới khi ai đó xóa một hàng cha và DB xóa mất nửa hệ thống. Cascade có thể đúng cho dữ liệu thật sự thuộc sở hữu (như dòng nháp không bao giờ tồn tại một mình), nhưng rủi ro cho các bản ghi quan trọng (khách hàng, hóa đơn, ticket). Nếu chưa chắc, ưu tiên RESTRICT và xử lý xóa một cách có chủ ý.

Vấn đề khác là viết CHECK quá hẹp. “Status phải là ‘new’, ‘won’, hoặc ‘lost’” nghe ổn cho tới khi bạn cần “paused” hoặc “archived”. Một CHECK tốt mô tả sự thật ổn định, không phải lựa chọn UI tạm thời. “amount >= 0” tồn tại tốt theo thời gian. “country in (...)” thì hiếm khi vậy.

Một vài vấn đề lặp lại khi team thêm ràng buộc sau khi mã sinh đã chạy:

  • Coi CASCADE như công cụ dọn dẹp, rồi xóa nhiều hơn dự định.
  • Làm CHECK quá hẹp chặn các trường hợp hợp lệ trong tương lai.
  • Nghĩ rằng UNIQUE ngăn trùng khi NULL còn tồn tại.
  • Thay đổi quy tắc mà không có kế hoạch sửa các hàng đã vi phạm.

Về hiệu năng: PostgreSQL tự động tạo index cho UNIQUE, nhưng foreign key không tự động index cột tham chiếu. Thiếu index, cập nhật và xóa trên cha có thể chậm vì Postgres phải quét bảng con để kiểm tra tham chiếu.

Trước khi thắt một quy tắc, tìm các hàng hiện có sẽ fail nó, quyết định sửa hay cách ly, và triển khai thay đổi từng bước.

Checklist nhanh và bước tiếp theo cho lần xây tiếp theo

Trước khi ship, dành năm phút cho mỗi bảng và ghi ra những gì phải luôn đúng. Nếu bạn nói được bằng tiếng Anh đơn giản, thường có thể thi hành bằng một ràng buộc.

Hỏi những câu này cho mỗi bảng:

  • Cái gì không bao giờ được NULL?
  • Cái gì không bao giờ được trùng?
  • Cái gì không bao giờ được âm hoặc ngoài phạm vi?
  • Cái gì không bao giờ tồn tại mà không có cha (không có hàng mồ côi)?
  • Cái gì luôn phải theo quy tắc đơn giản (trạng thái cho phép, bắt đầu trước kết thúc)?

Nếu bạn dùng công cụ xây dựng theo chat, coi những bất biến đó là tiêu chí chấp nhận cho dữ liệu, không phải ghi chú tùy chọn. Ví dụ: “Giá trị deal phải >= 0”, “Email contact là duy nhất theo workspace”, “Một task phải tham chiếu contact thực”. Càng rõ ràng thì càng ít chỗ cho các trường hợp biên vô tình.

Koder.ai (koder.ai) bao gồm các tính năng như chế độ lập kế hoạch, snapshot và rollback, và xuất mã nguồn, giúp bạn dễ lặp schema an toàn khi siết ràng buộc theo thời gian.

Một mẫu triển khai đơn giản hiệu quả với các team thực: chọn một bảng giá trị cao (users, orders, invoices, contacts), thêm 1-2 ràng buộc ngăn các lỗi tệ nhất (thường NOT NULLUNIQUE), sửa các ghi bị fail, rồi lặp lại. Thắt quy tắc theo thời gian tốt hơn một migration lớn rủi ro.

Câu hỏi thường gặp

Tại sao tôi nên đặt quy tắc dữ liệu trong PostgreSQL thay vì chỉ trong ứng dụng?

Hãy đặt các quy tắc luôn phải được tuân thủ trong PostgreSQL, rồi để mọi luồng của ứng dụng tuân theo chúng. Việc kiểm tra ở giao diện và API có thể đưa ra thông báo thân thiện, còn các ràng buộc sẽ chặn những lần ghi không hợp lệ từ quá trình nhập dữ liệu, tác vụ nền, lần thử lại và công cụ quản trị.

Khi nào tôi nên dùng NOT NULL?

Dùng NOT NULL khi một hàng không có ý nghĩa nếu thiếu giá trị, chẳng hạn như ID chủ sở hữu, tên hoặc thời điểm tạo. Đừng dùng chuỗi rỗng để thay cho thông tin người dùng chưa nhập vì điều đó che giấu lỗi.

Ràng buộc CHECK dùng để làm gì?

Dùng CHECK cho các quy tắc trong một hàng, chẳng hạn như amount >= 0, một trạng thái được phép hoặc ngày kết thúc sau ngày bắt đầu. Hãy giữ quy tắc ngắn gọn và ổn định để những thay đổi sản phẩm sau này không biến dữ liệu hợp lệ thành lỗi.

UNIQUE có ngăn các giá trị bị thiếu không?

Thêm UNIQUE khi các giá trị trùng lặp có thể gây ra vấn đề thực sự, chẳng hạn như ID bên ngoài bị lặp hoặc hai liên hệ có cùng email trong một tài khoản. Kết hợp với NOT NULL nếu mọi bản ghi đều phải có giá trị đó, vì PostgreSQL cho phép nhiều giá trị NULL theo một ràng buộc duy nhất tiêu chuẩn.

Khóa ngoại ngăn bản ghi mồ côi như thế nào?

Khóa ngoại khiến cơ sở dữ liệu từ chối một hàng con trỏ đến hàng cha không tồn tại. Nó ngăn các bản ghi mồ côi, chẳng hạn như một giao dịch không có công ty hợp lệ hoặc một ghi chú liên kết với khách hàng đã bị xóa.

Tôi có nên dùng ON DELETE CASCADE ở mọi nơi không?

Hãy bắt đầu với RESTRICT khi việc xóa bản ghi cha cần một quyết định có chủ đích. Chỉ chọn CASCADE khi các bản ghi con thực sự không còn giá trị nếu thiếu bản ghi cha đó, chẳng hạn như các mục bản nháp tạm thời.

Làm thế nào để chặn email trùng nhau nhưng khác chữ hoa chữ thường?

Dùng chỉ mục duy nhất trên giá trị đã chuẩn hóa, ví dụ lower(email), khi người dùng kỳ vọng việc viết hoa hay viết thường khác nhau vẫn là cùng một email. Hãy cắt khoảng trắng và chuẩn hóa dữ liệu đầu vào trong ứng dụng nữa để người dùng nhận được thông báo lỗi rõ ràng hơn.

Làm thế nào để thêm ràng buộc vào cơ sở dữ liệu production một cách an toàn?

Trước hết, hãy tìm các hàng vi phạm quy tắc mới. Sửa, gộp hoặc cách ly chúng theo từng lô, rồi thêm ràng buộc và cập nhật ứng dụng để hiển thị lỗi hữu ích khi thao tác ghi thất bại.

Khóa ngoại có cần chỉ mục không?

Ràng buộc duy nhất tự tạo chỉ mục riêng, nhưng khóa ngoại không tự động lập chỉ mục cột con. Hãy thêm chỉ mục vào cột tham chiếu khi bảng lớn hoặc khi các hàng cha thường xuyên được cập nhật hay xóa.

Tôi nên thêm những ràng buộc nào trước?

Hãy bắt đầu với một bảng ảnh hưởng đến tiền bạc, khách hàng hoặc danh tính. Thêm một hoặc hai quy tắc có giá trị rõ ràng, chẳng hạn như chủ sở hữu bắt buộc, email duy nhất theo từng tài khoản hoặc số tiền không âm, rồi kiểm tra các thao tác ghi lẽ ra phải thất bại.

Related posts