1. Database Normalization là gì?
Database Normalization (chuẩn hóa dữ liệu) là quá trình tổ chức dữ liệu thành các bảng và quan hệ hợp lý nhằm giảm dư thừa không cần thiết, tránh dữ liệu mâu thuẫn và duy trì tính toàn vẹn của database.
Khi thiết kế database, nếu lưu tất cả thông tin vào một bảng lớn, ban đầu việc truy vấn có thể có vẻ đơn giản. Nhưng khi dữ liệu tăng lên, một thông tin có thể bị lặp lại ở nhiều dòng, khiến việc cập nhật trở nên phức tạp và dễ phát sinh lỗi.
Ví dụ, một cửa hàng lưu đơn hàng cùng tên khách hàng và tên sản phẩm trong cùng một bảng. Khi một khách hàng tạo nhiều đơn hàng, tên và email của họ sẽ bị lặp lại. Nếu email thay đổi mà chỉ một số dòng được cập nhật, database sẽ chứa dữ liệu không nhất quán.
Normalization giải quyết vấn đề này bằng cách xác định mỗi thông tin thực sự thuộc về đâu, sau đó phân chia dữ liệu thành các bảng với quan hệ rõ ràng.
Ba dạng chuẩn thường cần nắm khi thiết kế relational database là:
- 1NF (First Normal Form): Mỗi trường chứa một giá trị phù hợp với miền dữ liệu, không tổ chức các nhóm giá trị lặp lại trong cùng một cấu trúc.
- 2NF (Second Normal Form): Đạt 1NF và loại bỏ sự phụ thuộc một phần vào khóa ghép.
- 3NF (Third Normal Form): Đạt 2NF và loại bỏ những phụ thuộc không khóa gây dư thừa, thường được giải thích thông qua phụ thuộc bắc cầu.
2. Vì sao cần Normalization?
Để hiểu các dạng chuẩn, trước tiên cần hiểu những vấn đề xảy ra khi dữ liệu bị tổ chức không hợp lý.
Data Redundancy – Dữ liệu dư thừa
Giả sử bảng lưu đơn hàng có cấu trúc:
| OrderID | CustomerName | CustomerEmail | ProductName |
|---|---|---|---|
| 1001 | John | [email protected] | Keyboard |
| 1001 | John | [email protected] | Mouse |
| 1002 | John | [email protected] | Monitor |
Tên và email của John xuất hiện nhiều lần. Nếu khách hàng có hàng trăm đơn hàng, cùng một thông tin sẽ được lưu lặp lại rất nhiều.
Update Anomaly
Giả sử John đổi email. Nếu application chỉ cập nhật một số dòng mà bỏ sót những dòng khác, database có thể chứa nhiều email khác nhau cho cùng một khách hàng.
Insert Anomaly
Nếu thông tin sản phẩm chỉ được lưu trong bảng order, có thể ứng dụng không lưu được sản phẩm mới khi chưa có đơn hàng nào chứa sản phẩm đó.
Delete Anomaly
Nếu khách hàng và sản phẩm chỉ xuất hiện trong các dòng đơn hàng, xóa dòng order cuối cùng có thể vô tình làm mất thông tin duy nhất đang lưu về một sản phẩm hoặc khách hàng.
Đây là delete anomaly: thao tác xóa một loại dữ liệu khiến một loại thông tin khác cũng bị mất ngoài ý muốn.
3. First Normal Form (1NF) – Mỗi trường chứa một giá trị phù hợp
1NF là dạng chuẩn đầu tiên của relational database. Theo cách học thực tế, một bảng nên có các hàng và cột rõ ràng, mỗi ô chứa một giá trị thuộc miền dữ liệu được xác định, và không tổ chức những nhóm cột lặp lại để chứa nhiều giá trị cùng loại.
Hãy xét một bảng lưu đơn hàng chưa được chuẩn hóa:
orderID CustomerName Products
1001 john keyboard, mouse
1002 john monitor,webcam
Vấn đề nằm ở column Products. Nó chứa nhiều sản phẩm trong cùng một ô. Database khó thực hiện những truy vấn có cấu trúc như tìm tất cả order chứa Mouse, đếm số lượng từng sản phẩm hoặc thiết lập foreign key đến bảng sản phẩm.
Một thiết kế khác cũng không hợp lý là dùng các cột cố định như:
OrderID
Product1
Product2
Product3
Cách này giới hạn số lượng sản phẩm và buộc schema phải thay đổi khi có nhiều trường hợp hơn.
4. Second Normal Form (2NF) – Phụ thuộc vào toàn bộ khóa
2NF yêu cầu bảng đã đạt 1NF và các thuộc tính không thuộc khóa phải phụ thuộc đầy đủ vào khóa, không chỉ phụ thuộc vào một phần của khóa ghép.
Điểm này thường gây nhầm lẫn: vấn đề của 2NF xuất hiện rõ nhất khi bảng sử dụng khóa ghép, tức primary key hoặc candidate key gồm nhiều thuộc tính.
Giả sử mỗi sản phẩm chỉ xuất hiện tối đa một dòng trong một order. Khi đó, khóa của bảng chi tiết là:
[
(OrderID, ProductID)
]
Ta phân tích sự phụ thuộc của từng thuộc tính:
OrderDate chỉ phụ thuộc vào OrderID, vì một order có một ngày tạo.
ProductName chỉ phụ thuộc vào ProductID, vì tên mô tả sản phẩm.
Quantity phụ thuộc vào cả OrderID và ProductID, vì số lượng là thuộc tính của một sản phẩm cụ thể trong một order.
Hai thuộc tính đầu chỉ phụ thuộc vào một phần của khóa ghép. Đây gọi là Partial Dependency (phụ thuộc một phần).
Nếu giữ bảng như cũ, ngày order bị lặp theo từng sản phẩm, còn tên sản phẩm lặp theo từng order. Bảng chứa thông tin thuộc về những entity khác nhau.
Chuyển từ 1NF sang 2NF
Tách bảng thành ba phần:
Orders lưu thông tin của mỗi order:
Orders
– OrderID (PK)
– OrderDate
Products lưu thông tin của mỗi sản phẩm:
Products
– ProductID (PK)
– ProductName
OrderItems lưu quan hệ giữa order và sản phẩm:
OrderItems
– OrderID (PK, FK)
– ProductID (PK, FK)
– Quantity
Ở đây, khóa ghép (OrderID, ProductID) của OrderItems xác định Quantity. Ngày tạo được lưu một lần ở Orders, còn tên sản phẩm được lưu một lần ở Products.
5. Third Normal Form (3NF) – Loại bỏ phụ thuộc bắc cầu không phù hợp
3NF yêu cầu bảng đạt 2NF và tránh những phụ thuộc không khóa khiến dữ liệu của một entity bị lưu lặp qua entity khác.
Một cách giải thích thường dùng là: các thuộc tính không khóa nên phụ thuộc vào khóa, toàn bộ khóa và không phụ thuộc thông qua một thuộc tính không khóa khác.
Giả sử OrderID là primary key. Ta có các phụ thuộc:
[
OrderID –> CustomerID
]
[
CustomerID –> CustomerName, CustomerEmail
]
Từ đó suy ra:
[
OrderID –> CustomerName, CustomerEmail
]
Nhưng tên và email không thực sự là thuộc tính của order. Chúng là thuộc tính của customer. Order chỉ lưu CustomerID để tham chiếu đến customer.
Đây là Transitive Dependency (phụ thuộc bắc cầu): OrderID xác định thông tin customer thông qua CustomerID.
Chuyển từ 2NF sang 3NF
Tách thông tin thành hai bảng:
Customers
– CustomerID (PK)
– CustomerName
– CustomerEmail
Orders
– OrderID (PK)
– OrderDate
– CustomerID (FK)
Giờ đây, tên và email được lưu ở Customers, còn Orders chỉ giữ khóa tham chiếu đến customer.
Khi John đổi email, database chỉ cần cập nhật thông tin ở bảng Customers, thay vì phải sửa từng order. Các order cũ vẫn liên kết với đúng customer thông qua CustomerID.
6. Denormalization – Khi chủ động lưu dữ liệu dư thừa
Denormalization (phi chuẩn hóa) là việc chủ động bổ sung hoặc giữ lại dữ liệu dư thừa có kiểm soát để phục vụ yêu cầu truy vấn, hiệu năng hoặc cách sử dụng dữ liệu của hệ thống.
Normalization ưu tiên cấu trúc và tính toàn vẹn của dữ liệu. Denormalization chấp nhận một số redundancy để giảm công việc cần thực hiện khi đọc hoặc tổng hợp dữ liệu.
Ví dụ, khi truy vấn một danh sách order, application có thể cần thông tin customer, order và các item. Nếu cấu trúc đã chuẩn hóa, dữ liệu có thể phải được ghép từ nhiều bảng bằng JOIN.
Ví dụ 1: Lưu tổng tiền đơn hàng
Giả sử OrderItems chứa giá và số lượng của từng sản phẩm. Tổng tiền cơ bản có thể được tính:
[
Total = \sum (Quantity \times UnitPrice)
]
Nếu mỗi lần hiển thị order đều tính lại tổng từ các item, application phải thực hiện phép tổng hợp. Một số hệ thống lưu sẵn orders.total_amount để đọc nhanh hơn hoặc giữ giá trị đã được chốt theo nghiệp vụ.
Khi nào nên Denormalize?
Denormalization thường chỉ nên xem xét khi có nhu cầu cụ thể, chẳng hạn query tổng hợp đang quá tốn kém, read workload rất lớn hoặc hệ thống cần một read model tối ưu cho giao diện và báo cáo.
Trước khi phi chuẩn hóa, nên đo query thực tế, đọc execution plan, xem index và đánh giá việc tối ưu SQL. Nếu truy vấn đã đủ nhanh, thêm dữ liệu dư thừa chỉ tăng độ phức tạp mà không mang lại lợi ích đáng kể.
Khi thực hiện Denormalization, cần trả lời ba câu hỏi: dữ liệu dư thừa được tạo ra để làm gì, khi dữ liệu nguồn thay đổi thì giá trị dư thừa được cập nhật như thế nào và application sẽ phát hiện hoặc khôi phục sai lệch ra sao.
7. Tổng kết
Database Normalization giúp tổ chức dữ liệu sao cho mỗi thông tin được lưu ở nơi phù hợp, giảm dư thừa gây lỗi và duy trì tính nhất quán.
1NF tập trung vào cách biểu diễn các giá trị và loại bỏ nhóm dữ liệu lặp không phù hợp. 2NF loại bỏ phụ thuộc một phần khi khóa có nhiều thuộc tính. 3NF xử lý những phụ thuộc không khóa, thường gặp nhất là trường hợp một thuộc tính không khóa được xác định thông qua thuộc tính không khóa khác.
BCNF là dạng chuẩn chặt chẽ hơn, hữu ích khi các quan hệ giữa candidate key và functional dependency phức tạp. Denormalization có mục tiêu khác: chủ động duy trì một số dữ liệu dư thừa để đáp ứng yêu cầu đọc, tổng hợp hoặc snapshot nghiệp vụ.








Khoá học lập trình game con rắn cho trẻ em




