Sau khi đã có những lý thuyết cơ bản về khóa và phụ thuộc hàm (Functional Dependency - FD), ta sẽ đi tiếp tới chuẩn thứ hai: The Second Normal Form - 2NF.
Từ dạng chuẩn 2NF này, dữ liệu bị dư thừa theo dạng sẽ dẫn tới các vấn đề về Update Anomalies (cập nhật dị thường).
Để khởi động, mình sẽ đề cập nhanh tới hiện tượng dị thường này đầu tiên.
Update Anomalies do thiếu 2NF
Ví dụ, ta có relation với data mẫu sau:
cab_no | date_driven | driver |
101 | 2/4/2023 | Rich |
102 | 2/4/2023 | Gen |
103 | 2/5/2023 | John |
102 | 2/5/2023 | Steph |
104 | 3/5/2023 | Rich |
Từ dữ liệu mẫu trên, có thể nhận định rằng relation này đã đạt chuẩn 1NF: không có cell nào chứa nhiều hơn 1 đối tượng của kiểu định nghĩa. Đây chỉ là "nhận định" vì ta đang có dữ liệu mẫu chứ không phải toàn bộ dữ liệu bảng.
Giờ hãy cùng xác định các FD tiềm năng:
- { cab_no } ⇒ { date_driven }: không thỏa mãn do cùng một giá trị cab_no = 102, có hai giá trị khác nhau của date_driven = { 2/4/2023, 2/5/2023 }.
- { cab_no } ⇒ { driver }: không thỏa mãn do cùng giá trị cab_no = 102, có hai giá trị khác nhau của driver = { Gen, Steph }.
- { date_driven } ⇒ { cab_no }: không thỏa mãn do cùng giá trị date_driven = 2/4/2023, có hai giá trị khác nhau của cab_no = { 101, 102 }.
- { date_driven } ⇒ { driver }: không thỏa mãn do cùng giá trị date_driven = 2/5/2023, có hai giá trị khác nhau của cab_no = .
{ cab_no, date_driven } ⇒ { driver }
: thỏa mãn là một FD.- { driver } ⇒ { date_driven }: không thỏa mãn do có cùng giá trị driver = Rich, có hai giá trị khác nhau của date_driven = .
Như vậy ta có một FD duy nhất: { cab_no, date_driven } ⇒ { driver }
Bây giờ, giả sử ta cần quản lý màu sắc của cab (là xe taxi), ta có bảng như sau:
cab_no | date_driven | driver | color |
101 | 2/4/2023 | Rich | Yellow |
102 | 2/4/2023 | Gen | Green |
103 | 2/5/2023 | John | Yellow |
102 | 2/5/2023 | Steph | Green |
104 | 3/5/2023 | Rich | Black |
Ta có thêm một FD nữa: { cab_no } ⇒ { color }
Như vậy relation có hai FD:
FD1: { cab_no, date_driven } ⇒ { driver }
FD2: { cab_no } ⇒ { color }
Insert
Nếu muốn thêm một xe mới vào relation này ta bắt buộc phải có tài xế.
Update
Nếu muốn cập nhật màu sắc của xe cab_no = 102 từ màu Green sang màu Red, ta phải cập nhật toàn bộ các dòng có sự xuất hiện của cab_no này. Nếu bỏ sót dù chỉ một dòng, dữ liệu sẽ rơi vào không nhất quán (inconsistent).
Hãy tưởng tượng, relation này là một dạng dữ liệu giao dịch nên theo thời gian nó sẽ có sự tăng trưởng mạnh về khối lượng dữ liệu. Cab_no = 102 sẽ tham gia nhiều giao dịch trong bảng trong suốt vòng đời sử dụng của nó. Do đó, khi cập nhật color, ta thường sẽ chạy một luồng background batch job: con job sẽ truy vấn từng đoạn dữ liệu, lấy ra cab_no = 102 để cập nhật màu sắc mới và rồi save xuống database theo từng batch. Không có gì đảm bảo con job này không bị chết giữa chừng, và khi đó, dữ liệu của ta sẽ không nhất quán.
Delete
Nếu muốn xa thông tin lái xe { date_driven, driver }, ta buộc phải xóa cả hai cột { cab_no, color }. Điều này dẫn đến mất mát dữ liệu về xe mặc dù vẫn cần thông tin này để sử dụng trong tương lai.
Giải quyết
Ta cần chuyển relation này về dạng 2NF. Công thức như sau:

Áp dụng công thức trên, ta có kết quả là hai bảng sau:
R1( cab_no, date_driven, driver ) và R2( cab_no, color )
cab_no | date_driven | driver |
101 | 2/4/2023 | Rich |
102 | 2/4/2023 | Gen |
103 | 2/5/2023 | John |
102 | 2/5/2023 | Steph |
104 | 3/5/2023 | Rich |
và
cab_no | color |
101 | Yellow |
102 | Green |
103 | Yellow |
104 | Black |
Khi relation đã đạt chuẩn 2NF, các vấn đề Update Anomalies bên trên sẽ biến mất.
Định nghĩa 1 - dễ hiểu
Relation R ở dạng 2NF khi và chỉ khi, với mọi key K và mọi thuộc tính non-key A của R:
FD: K ⇒ A không thể rút gọn.
Dù là "dễ hiểu" nhưng nếu chưa quen, bạn vẫn thấy khá khó hiểu. Tôi sẽ giải thích thêm.
- Định nghĩa đề cập tới "mọi key K" nghĩa là bất kỳ một candidate key nào trong R đều phải đưa vào đối chiếu. Trong ví dụ của ta, ta có key là
- Candidate key: { cab_no, date_driven }
- Thuộc tính non-key tương ứng với từng key bên trên và FD tương ứng:
- Candidate key:
- FD1: { cab_no, date_driven } ⇒ { driver }
- FD2: { cab_no, date_driven } ⇒ { color }
- FD3: { cab_no, date_driven } ⇒ { driver, color }
- Candidate key:
- FD nào bên trên không thể rút gọn? Nếu tất cả ba FD này đều không thể rút gọn thì relation sẽ thỏa mãn 2NF.
- Rút gọn là gì? là khi ta bỏ bớt thuộc tính trong tập K mà vẫn đảm bảo xác định được A.
- Do ta có FD: { cab_no } ⇒ { color } nên FD2 có thể rút gọn bằng cách loại bỏ date_driven.
- FD3 ta không cần xét do nó là kết quả của phép hợp FD2 và FD2 (xem lại trong phần Phụ thuộc hàm).
- Vậy relation không thỏa mãn 2NF.
Giải thích định nghĩa:
Định nghĩa này cho thấy hai điều:
- Mọi thuộc tính trong A phải phụ thuộc trực tiếp vào K.
- Không có phụ thuộc hàm một phần (PD) nào tồn tại, tức là không có thuộc tính không khóa nào phụ thuộc vào một phần của khóa chính.
Định nghĩa 2 - chặt chẽ
Ta cùng đi tới định nghĩa chặt chẽ hơn:
Relation R ở dạng 2NF khi và chỉ khi, với mọi phụ thuộc hàm FD không tầm thường X ⇒ Y của R, ít nhất một trong ba điều kiện sau là đúng:
• X là một Superkey
• Y là một Subkey
• X không phải là Subkey
Lại càng khó hiểu hơn nữa dù có thể bạn đã nắm được khái niệm superkey, subkey.
- Đầu tiên, mọi FD X ⇒ Y trong R đều được đưa vào xem xét và chúng phải là không tầm thường (Y không phải là tập con của X).
- Với từng FD, chỉ cần thỏa mãn một trong ba điều kiện đó thì R sẽ ở dạng 2NF, còn nếu chỉ một FD không thỏa mãn bất kỳ điều kiện nào, R sẽ không đạt.
- X là một superkey: điều kiện này cho thấy mọi thuộc tính Y sẽ là thuộc tính không khóa còn mọi thuộc tính trong X sẽ là thuộc tính trong khóa (prime attributes). Phụ thuộc này mang lại chuẩn hóa mạnh mẽ (sau bạn sẽ thấy, nếu toàn bộ FD thỏa mãn điều này thì R sẽ đạt chuẩn BCNF - cao hơn 2NF)
- Y là một subkey: điều này cho thấy mọi thuộc tính Y sẽ không phải là thuộc tính ngoài khóa mà nó là trong khóa. Bạn thấy khó hiểu vì FD là không tầm thường mà, nếu Y là thuộc tính trong khóa thì chẳng phải FD này là tầm thường sao? Nhưng hãy để ý kỹ lại, định nghĩa không quy định X phải là khóa. Do đó, bạn thấy rằng trường hợp này là thuộc tính trong khóa phụ thuộc vào thuộc tính ngoài khóa. Relation vẫn đạt chuẩn 2NF.
- X không phải là subkey: Nếu X là subkey, đó chính là phụ thuộc thành phần rồi.
- Quan sát 3 điều kiện này, các bạn sẽ thấy rằng sự chặt chẽ hay cấp độ chuẩn hóa được hạ thấp dần từ trên xuống.
Ví dụ
Với định nghĩa này, ta nên đi qua ví dụ để hiểu rõ hơn về cách áp dụng.
Xem xét relation trong ví dụ trên với các FD không tầm thường sau:
- FD1: { cab_no, date_driven } ⇒ { driver }
- FD2: { cab_no, date_driven } ⇒ { color }
- FD3: { cab_no } ⇒ { color }
X là một superkey | Y là một subkey | X không phải là subkey | |
FD1: { cab_no, date_driven } ⇒ { driver } | TRUE | FALSE | TRUE |
FD2: { cab_no, date_driven } ⇒ { color } | TRUE | FALSE | TRUE |
FD3: { cab_no } ⇒ { color } | FALSE | FALSE | FALSE |
Nhìn vào bảng 5, các điều kiện nằm tại 3 cột cuối, còn các FD được xếp theo hàng. Theo định nghĩa thì relation đạt chuẩn 2NF khi cả ba FD này đều có ít nhất một giá trị TRUE.
Trong khi FD1 và FD2 đều có TRUE thì FD3 lại toàn FALSE. Do đó bảng này không đạt chuẩn 2NF.
-----------
Tham khảo: