Những sai lầm trong thiết kế cơ sở dữ liệu
Bài đăng này đã không được cập nhật trong 7 năm
Là một lập trình viên, bất kể khi nào được giao một task nào đó dựa trên code có sẵn, bạn thường sẽ gặp phải rất nhiều thách thức. Một trong số đó liên quan đến việc hiểu mô hình dữ liệu (data model) của ứng dụng. Bạn sẽ mất một khoảng thời gian để hiểu về các bảng, các cột, giá trị cũng như những ràng buộc, thủ tục lưu trữ, hàm hay triggers,… Một khi đã hiểu về chúng, bạn bắt đầu nhận thấy có nhiều cách để cải thiện và tận dụng được các thông tin được lưu trữ. Nếu là một lập trình viên có kinh nghiệm, có thể bạn cũng sẽ thấy mọi thứ đáng lẽ ra có thể được làm tốt hơn ngay từ đầu, chẳng hạn như là thiết kế cơ sở dữ liệu. Bài viết này sẽ chỉ ra những sai lầm trong thiết kế cơ sở dữ liệu (CSDL) và cách để tránh gặp phải những sai lầm này.
1. Bỏ qua mục đích của dữ liệu
Dữ liệu được lưu trữ để sử dụng về sau và mục tiêu là luôn lưu và nhận dữ liệu sao cho hiểu quả nhất. Để thực hiện điều này, người thiết kế CSDL phải biết trước được dữ liệu là gì, được lấy ra làm sao, quy mô của dữ liệu và dữ liệu được sử dụng như nào. Ví dụ, một hệ thống có dữ liệu thu thập hàng ngày không thể có mô hình dữ liệu giống hệ thống có dữ liệu được sinh ra theo thời gian thực. Bởi cách xử lý dữ liệu với quy mô hàng ngàn bản ghi trên tháng sẽ rất khác với quản lý hàng triệu bản ghi trên cùng một chu kỳ thời gian như vậy. Người thiết kế cần cân nhắc thật kỹ về tính hiệu quả cũng như mức độ sử dụng của dữ liệu nếu quy mô của dữ liệu là lớn. Tuy nhiên, quy mô dữ liệu không phải là khía cạnh duy nhất cần cân nhắc bởi mục đích của dữ liệu cũng ảnh hưởng tới mức độ chuẩn hóa, cấu trúc dữ liệu, kích cỡ bản ghi và việc cài đặt chung cho toàn bộ hệ thống. Do đó, hiểu rõ mục đích của hệ thống dữ liệu sẽ giúp bạn đưa ra những cân nhắc đúng đắn về việc lựa chọn database engines hay những thực thể để thiết kế hoặc kích cỡ và dữ liệu bản ghi, chính sách quản lý database engine. Việc bỏ qua mục đích sử dụng của dữ liệu sẽ dẫn đến những thiết kế không tốt, dù chúng có thể đúng về mặt cấu trúc hay toán học.
2. Chuẩn hóa yếu
Thiết kế cơ sở dữ liệu không phải là công việc có tính xác định; hai người thiết kế CSDL có thể áp dụng những quy tắc và nguyên lý chuẩn hóa giống nhau cho cùng một vấn đề nhưng mô hình dữ liệu cuối cùng có thể không giống nhau. Điều này thể hiện sự sáng tạo tự nhiên của công nghệ phần mềm. Tuy nhiên, có một vài kỹ thuật phân tích mà đúng trong mọi trường hợp và việc áp dụng chúng là cách tốt nhất để CSDL đạt hiệu năng cao nhất. Mặc dù vậy, chúng ta thường thấy những CSDL được thiết kế mà không áp dụng theo những quy tắc chuẩn hóa cơ bản nhất. Chúng ta phải biết rõ rằng: Mọi CSDL nên ít nhất được chuẩn hóa theo dạng 3NF vì đó là mô hình tốt nhất để thể hiện các thực thể dữ liệu và sẽ cân bằng được hiệu năng truy vấn và thêm-sửa-xóa bản ghi. Nếu bạn có lỡ không tuân theo chuẩn 3NF, 2NF hay thậm chí 1NF thì nên cân nhắc việc thiết kế lại CSDL. Điều này sẽ không tốn quá nhiều thời gian để tìm hiểu và nghiên cứu.
3. Sự dư thừa
Khá liên quan tới phần trên, bởi một trong những mục tiêu của chuẩn hóa là giảm thiểu sự dư thừa. Đây là một sai lầm khác thường gặp. Các bảng và trường dư thừa là một ác mộng một đối với lập trình viên vì chúng yêu cầu phần xử lý nghiệp vụ cập nhật các thông tin giống nhau ở nhiều phiên bản. Điều này sẽ được tránh khỏi nếu các quy tắc chuẩn hóa được áp dụng. Mặc dù đôi khi sự dư thừa có vẻ là cần thiết, thì nhất định nó chỉ được sử dụng trong những trường hợp hết sức cụ thể và được chỉ rõ trong tài liệu đặc tả để những lập trình viên về sau này cân nhắc. Những tác động xấu điển hình của sự dư thừa là gia tăng kích cỡ CSDL một cách không cần thiết, dữ liệu dễ bị mất tính ổn định, và giảm hiệu quả của CSDL. Thậm chí nó có thể dẫn đến hỏng dữ liệu.
4. Ràng buộc yếu
Ràng buộc là một trong những yếu tố quan trọng nhất mà database engines đảm bảo cho dữ liệu được chất lượng tốt nhất. Nếu không có ràng buộc hoặc rất ít ràng buộc được thiết lập trong giai đoạn thiết kế, thì tính bảo toàn của dữ liệu sẽ phải dựa hoàn toàn vào phần logic nghiệp vụ, khiến dữ liệu dễ bị ảnh hưởng bởi những lỗi do con người gây ra.
5. Không tận dụng những tính năng của DB Engine
Database engine (DBE) là một công cụ xử lý dữ liệu mạnh mẽ giúp đơn giản hóa việc phát triển phần mềm cũng như đảm bảo thông tin luôn chính xác, an toàn và dễ sử dụng. Một DBE cung cấp những dịch vụ như:
- Views cho phép duyệt dữ liệu một cách nhanh chóng và hiệu quả, bỏ chuẩn hóa để truy vấn mà không làm mất độ chính xác của dữ liệu.
- Chỉ mục giúp tăng tốc truy vấn ở các bảng.
- Các hàm tập hợp giúp phân tích thông tin mà không cần lập trình quá phức tạp.
- Transactions: giúp bảo toàn dữ liệu khi có lỗi xảy ra.
- Locks giúp dữ dữ liệu được an toàn và chính xác khi transactions được thực thi.
- Thủ tục lưu trữ cung cấp tính năng lập trình để xử lý những công việc quản lý dữ liệu phức tạp.
- Hàm cho phép tính toán và chuyển đổi dữ liệu phức tạp
- Ràng buộc giúp bảo toàn độ chính xác của dữ liệu và tránh lỗi.
- Triggers giúp tác vụ được thực hiện tự động khi có sự kiện xảy ra trên dữ liệu.
- Công cụ tối ưu lệnh đảm bảo mọi câu lệnh được chạy hiệu quả và sử dụng cho những tình huống về sau này. Việc không biết hoặc bỏ qua những tính năng này sẽ khiến việc phát triển trở nên khó khăn cũng như những lỗi và vấn đề về sau.
6. Khóa chính kết hợp
Đây là một điểm gây tranh cãi, bởi nhiều người thiết kế CSDL ngày này thường nói về việc sử dụng trường số nguyên ID được sinh tự động làm khóa chính thay vì khóa được tạo bởi việc kết hợp từ 2 trường trở lên. Tuy nhiên, đây dĩ nhiên chỉ là một convention, các DBE cho phép định nghĩa các khóa chính kết hợp, điều mà nhiều người thiếtt kế nghĩ là không tránh khỏi. Do đó, như sự dư thừa, có sử dụng khóa chính kết hợp hay không là tùy vào từng quyết định thiết kế. Nhưng nếu bảng dùng khóa chính kết hợp có hàng triệu bản ghi, dẫn đến chỉ mục trên các trường khóa gia tăng tới một mức nào đó mà khiến hiệu năng của việc thao tác với dữ liệu (đọc, thêm, sửa, xóa) suy giảm. Trong trường hợp đó, tốt hơn hết là sử dụng khóa chính ID mà chỉ mục của nó đủ nhỏ gọn và sinh ra những ràng buộc DBE cần thiết để duy trì tính duy nhất.
7. Chỉ mục yếu
Đôi khi, bảng dữ liệu cần truy vấn trên nhiều cột. Khi dữ liệu nhiều lên, truy vấn SELECT
trở lên chậm đi. Đến một lúc nào đó, khi dữ liệu đủ lớn, bạn sẽ nghĩ tới việc tạo chỉ mục trên mỗi cột để gia tăng hiệu năng truy vấn SELECT
nhưng đồng nghĩa với việc hiệu năng của INSERT
, UPDATE
, và DELETE
sẽ đi xuống. Điều này là hiển nhiên bởi thực thế chỉ mục phải được đồng bộ với các bảng, khiến DBE hoạt động nhiều hơn. Đây là một trường hợp điển hình về xử lý vấn đề chỉ mục theo nhiều cách. Ví dụ: chỉ có một chỉ mục cho tất cả các cột, ngoại trừ cột khóa chính, sắp xếp theo thứ tự từ cột được sử dụng nhiều nhất đến ít nhất.
Ngoài ra, hiệu quả của chỉ mục đôi khi còn phụ thuộc vào kiểu dữ liệu. Chỉ mục trên các cột INT
cho hiệu năng cao nhất trong khi chỉ mục trên VARCHAR
, DATE
hay DECIMAL
thì không. Việc cân nhắc này thậm chí có thể dẫn đến việc thiết kế lại bảng mà cần truy cập với hiệu năng cao nhất có thể.
Do đó, chỉ mục cần sự quyết định khéo léo, quá nhiều chỉ mục có thể hại như quá ít chỉ mục và bởi kiểu dữ liệu của cột để đánh chỉ mục có ảnh hưởng lớn đến đầu ra cuối cùng.
8. Quy tắc đặt tên không tốt
Có một điều mà lập trình viên luôn phải vật lộn khi đối mặt với một CSDL có sẵn: cố gắng để hiểu thông tin được lưu trữ bên trong CSDL dựa vào tên của bảng và các cột. Và thông thường thì không có cách nào khác. Tên của bảng phải mô tả được thực thể mà nó đã nắm giữ và tên mỗi cột phải mô tả được phần thông tin mà nó đang thể hiện. Điều này có vẻ dễ dàng nhưng lại bắt đầu trở lên phức tạp khi các bảng có quan hệ với nhau. Tên gọi trở nên hỗn độn và tệ hơn là có những quy tắc đặt tên với những định mức không hợp lý (ví như “tên cột không được quá 8 ký tự”). Hệ quả là CSDL trở nên khó hiểu. Do vậy, quy tắc đặt tên là luôn cần thiết nếu CSDL kéo dài và phát triển cùng với ứng dụng mà nó hỗ trợ. Đây là một số hướng dẫn để đặt tên một cách đơn giản, ngắn gọn và dễ đọc:
- Không giới hạn kích cỡ tên bảng/cột. Một cách tên ý nghĩa sẽ dễ hiểu và dễ nhớ hơn tên viết tắt.
- Tên giống nhau có cùng một ý nghĩa. Tránh đặt tên cho các trường giống nhau với những kiểu dữ liệu hoặc ý nghĩa khác nhau.
- Nếu không cần thiết, loại bỏ sự dừ thừa. Ví dụ trong bảng
Item
, thay vìItemName
,PriceOfItem
, hoặc tương tự thìName
vàPrice
là đủ. - Tránh những từ khóa mặc định của DBE. Nếu một cột được gọi là
Index
, một từ khóa của SQL, thì cố gắng sử dụng một cái tên khác nhưIndexNumber
. - Nếu sử dụng khóa chính là cột số nguyên được sinh tự động, đặt tên cho nó là
Id
ở mọi bảng. - Định nghĩa khóa ngoài khi nối bảng: thêm
Id
đằng trước tên bảng. Ví dụIdItem
. - Nếu đặt tên cho ràng buồng thì sử dụng tiền tố mô tả ràng buộc (vd:
PK
hoặcFK
), theo sau là tên của bảng hoặc bảng liên quan. Dĩ nhiên, việc sử dụng gạch dưới_
phần nào đó khiến mọi thứ trở nên dễ đọc hơn. - Để đặt tên cho chỉ mục, sử dụng tiền tố
IDX
đằng trước tên bảng và tên cột hoặc cột của chỉ mục. Đồng thời sử dụngUNIQUE
làm tiền tố hoặc hậu tố nếu chỉ mục là duy nhất và sử dụng gạch dưới nếu cần thiết. Có nhiều quy tắc đặt tên khác sẽ cụ thể hơn nhưng với những quy tắc cơ bản này, CSDL sẽ trở nên dễ đọc hơn. Điều quan trọng không phải là quy mô hay độ phức tạp của những quy tắc đặt tên mà là sự nhất quán khi áp dụng chúng.
Kết luận
Thiết kế CSDL đòi hỏi kết hợp giữa kiến thức và kinh nghiệm khi mà ngành công nghiệp phần mềm đang ngày càng phát triển hiện nay. Thật may là có đủ sẵn kiến thức để giúp các nhà thiết kế CSDL cho ra những kết quả tốt nhất. Đó có thể là những hướng dẫn để giúp thiết kế CSDL tốt, cũng có thể là hướng dẫn chỉ ra những sai lầm và những điều nên tránh. Tự mỗi bản thân chúng ta hay lựa chọn và đi theo một hướng dẫn nào đó.
Tham khảo (Lược dịch) Fernando Martinez, Bad Practices in Database Design: Are You Making These Mistakes?, https://www.toptal.com/database/database-design-bad-practices
All rights reserved