Bài 8. Khóa chính, khóa ngoại và thiết kế quan hệ

Khóa là thứ làm CSDL “quan hệ”. Bài này học khóa chính, khóa ngoại, các kiểu quan hệ 1-1, 1-n, n-n, hành vi ON DELETE/ON UPDATE, chỉ mục và chuẩn hóa dữ liệu cơ bản để tránh trùng lặp.

45 phútTrung cấp
Bạn sẽ học được
  • Tạo khóa chính đơn và khóa chính kép
  • Tạo khóa ngoại với ON DELETE CASCADE/SET NULL/RESTRICT
  • Mô hình hóa quan hệ 1-n và n-n bằng bảng trung gian
  • Hiểu chỉ mục và chuẩn hóa 1NF–3NF ở mức cơ bản
Thuật ngữ cần biết
Khóa chính (PK)
Cột định danh duy nhất mỗi dòng.
Khóa ngoại (FK)
Cột tham chiếu khóa chính bảng khác.
Toàn vẹn tham chiếu
Không được trỏ tới dòng không tồn tại.
Chuẩn hóa
Tách bảng để tránh lặp và mâu thuẫn dữ liệu.

Khái niệm và lý thuyết

Khóa ngoại bảo đảm toàn vẹn tham chiếu: không thể thêm sinh viên vào lớp không tồn tại, không thể xóa lớp đang có sinh viên (trừ khi khai báo CASCADE). Quan hệ: 1-n (một lớp nhiều sinh viên: FK đặt ở bảng “nhiều”), n-n (sinh viên học nhiều môn, môn có nhiều sinh viên: cần bảng trung gian diem chứa hai FK), 1-1 (sinh viên và hồ sơ chi tiết: FK UNIQUE).

Khóa chính

CREATE TABLE lop (
  id INT AUTO_INCREMENT PRIMARY KEY, ...
);
-- Khóa chính kép (bảng trung gian không cần id riêng)
CREATE TABLE dang_ky (
  sinhvien_id INT, monhoc_id INT, hoc_ky VARCHAR(10),
  PRIMARY KEY (sinhvien_id, monhoc_id, hoc_ky)
);
ALTER TABLE monhoc ADD PRIMARY KEY (id);   -- thêm sau

Khóa ngoại và hành vi

CREATE TABLE sinhvien (
  id INT AUTO_INCREMENT PRIMARY KEY,
  ho_ten VARCHAR(100) NOT NULL,
  lop_id INT,
  CONSTRAINT fk_sv_lop FOREIGN KEY (lop_id) REFERENCES lop(id)
    ON DELETE SET NULL        -- xóa lớp: sinh viên còn, lop_id thành NULL
    ON UPDATE CASCADE         -- đổi id lớp: tự cập nhật
);
CREATE TABLE diem (
  id INT AUTO_INCREMENT PRIMARY KEY,
  sinhvien_id INT NOT NULL,
  monhoc_id INT NOT NULL,
  diem DECIMAL(4,2),
  FOREIGN KEY (sinhvien_id) REFERENCES sinhvien(id) ON DELETE CASCADE,   -- xóa SV: xóa điểm theo
  FOREIGN KEY (monhoc_id)  REFERENCES monhoc(id)   ON DELETE RESTRICT,   -- không cho xóa môn còn điểm
  UNIQUE (sinhvien_id, monhoc_id)                                        -- mỗi SV mỗi môn một điểm
);
ALTER TABLE sinhvien ADD CONSTRAINT fk_sv_lop FOREIGN KEY (lop_id) REFERENCES lop(id);
ALTER TABLE sinhvien DROP FOREIGN KEY fk_sv_lop;
Hành viKhi xóa/sửa dòng cha
RESTRICT / NO ACTIONTừ chối nếu còn dòng con (mặc định)
CASCADEXóa/sửa dòng con theo
SET NULLĐặt FK của dòng con thành NULL

Quan hệ n-n

-- Sinh viên <-> Môn học qua bảng diem (hoặc dang_ky)
sinhvien (id, ho_ten)        monhoc (id, ten_mon)
            \                    /
             diem (sinhvien_id, monhoc_id, diem, hoc_ky)

-- Câu hỏi "An học môn gì?" -> JOIN qua bảng trung gian
SELECT m.ten_mon FROM monhoc m
JOIN diem d ON d.monhoc_id = m.id
JOIN sinhvien sv ON sv.id = d.sinhvien_id
WHERE sv.ho_ten = 'Lò Văn An';

Chỉ mục (INDEX)

CREATE INDEX idx_sv_ho_ten ON sinhvien (ho_ten);
CREATE INDEX idx_diem_sv_mon ON diem (sinhvien_id, monhoc_id);
SHOW INDEX FROM sinhvien;
EXPLAIN SELECT * FROM sinhvien WHERE ho_ten = 'Lò Văn An';   -- xem có dùng chỉ mục không
DROP INDEX idx_sv_ho_ten ON sinhvien;

Chỉ mục như mục lục sách: tìm kiếm, JOIN, ORDER BY nhanh hơn nhiều với bảng lớn, đổi lại INSERT/UPDATE chậm hơn chút và tốn dung lượng. Khóa chính, UNIQUE, khóa ngoại tự có chỉ mục. Đánh chỉ mục cho cột hay dùng trong WHERE/JOIN.

Chuẩn hóa cơ bản

Dạng chuẩnYêu cầuVí dụ vi phạm
1NFMỗi ô một giá trị, không lặp cộtCột mon_hoc = "Web, CSDL, Python"
2NFMọi cột phụ thuộc toàn bộ khóa chínhBảng diem(sv_id, mon_id, ten_sv): ten_sv chỉ phụ thuộc sv_id
3NFKhông phụ thuộc bắc cầuBảng sinhvien có ten_lop và khoa: khoa phụ thuộc lớp, không phụ thuộc SV

Dấu hiệu cần tách bảng: cùng một thông tin được gõ lặp ở nhiều dòng (tên lớp ở mọi sinh viên). Tách thành bảng riêng và tham chiếu bằng FK.

Mẹo hay

Trong phpMyAdmin, tab Designer vẽ sơ đồ quan hệ từ các khóa ngoại đã khai báo: rất hữu ích để kiểm tra thiết kế và đưa vào báo cáo đồ án.

Lưu ý

Khóa ngoại chỉ hoạt động với engine InnoDB và hai cột phải cùng kiểu (INT với INT, cùng dấu). Lỗi “Cannot add foreign key constraint” thường do khác kiểu hoặc bảng cha chưa có chỉ mục.

Thực hành
  1. Thêm bảng khoa(id, ten_khoa) và sửa lop tham chiếu khoa bằng FK.
  2. Thử xóa một lớp đang có sinh viên và quan sát lỗi; đổi sang ON DELETE SET NULL.
  3. Thiết kế CSDL thư viện (sach, the_loai, doc_gia, phieu_muon, chi_tiet_muon) với đầy đủ khóa.
  4. Dùng EXPLAIN so sánh truy vấn theo ho_ten trước và sau khi tạo chỉ mục.
Tóm tắt bài học
  • PK định danh dòng; FK bảo đảm toàn vẹn tham chiếu.
  • 1-n: FK ở bảng nhiều; n-n: bảng trung gian hai FK; 1-1: FK UNIQUE.
  • ON DELETE CASCADE / SET NULL / RESTRICT theo nghiệp vụ.
  • Chỉ mục cho cột tìm kiếm; chuẩn hóa để tránh lặp dữ liệu.