Tôi chưa thực hiện một nghiên cứu chính thức, nhưng từ kinh nghiệm của bản thân, tôi đoán rằng hơn 80% lỗi thiết kế cơ sở dữ liệu được tạo ra từ việc thiết kế với hiệu suất là yếu tố quan trọng nhất (nếu không phải là duy nhất) được xem xét.
Nếu một thiết kế tốt yêu cầu nhiều bảng, hãy tạo nhiều bảng. Đừng tự động cho rằng liên kết là điều nên tránh. Chúng hiếm khi là nguyên nhân thực sự của các vấn đề về hiệu suất.
Cân nhắc chính, đầu tiên và quan trọng nhất trong tất cả các giai đoạn của thiết kế cơ sở dữ liệu, là tính toàn vẹn của dữ liệu. "Câu trả lời có thể không phải lúc nào cũng đúng, nhưng chúng tôi có thể đưa nó cho bạn rất nhanh" không phải là mục tiêu mà bất kỳ cửa hàng nào cũng nên hướng tới. Sau khi tính toàn vẹn dữ liệu bị khóa, nếu hiệu suất trở thành vấn đề , nó có thể được giải quyết. Đừng hy sinh tính toàn vẹn của dữ liệu, đặc biệt là để giải quyết các vấn đề có thể không tồn tại.
Với suy nghĩ đó, hãy xem những gì bạn cần. Bạn có những quan sát bạn cần lưu trữ. Những quan sát này có thể khác nhau về số lượng và loại thuộc tính và có thể là những thứ như giá trị của phép đo, thông báo về một sự kiện và sự thay đổi trạng thái, trong số những quan sát khác và với khả năng thêm các quan sát trong tương lai.
Điều này có vẻ phù hợp với một mẫu "loại / loại phụ" tiêu chuẩn, với mục nhập "Quan sát" là loại và mỗi loại hoặc loại quan sát là loại phụ và đề xuất một số dạng trường chỉ báo loại như:
create table Observations(
...,
ObservationKind char( 1 ) check( ObservationKind in( 'M', 'E', 'S' )),
...
);
Nhưng mã hóa cứng một danh sách như thế này trong một ràng buộc kiểm tra có mức độ bảo trì rất thấp. Nó trở thành một phần của lược đồ và chỉ có thể được thay đổi bằng các câu lệnh DDL. Không phải là thứ mà DBA của bạn sẽ mong đợi.
Vì vậy, hãy có các loại quan sát trong bảng tra cứu của riêng chúng:
ID Name Meaning
== =========== =======
M Measurement The value of some system metric (CPU_Usage).
E Event An event has been detected.
S Status A change in a status has been detected.
(Trường char cũng có thể là int hoặc smallint. Tôi sử dụng char ở đây để minh họa.)
Sau đó, điền vào bảng Quan sát bằng PK và các thuộc tính chung cho tất cả các quan sát.
create table Observations(
ID int identity primary key,
ObservationKind char( 1 ) not null,
DateEntered date not null,
...,
constraint FK_ObservationKind foreign key( ObservationKind )
references ObservationKinds( ID ),
constraint UQ_ObservationIDKind( ID, ObservationKind )
);
Có vẻ hơi lạ khi tạo một chỉ số duy nhất trên sự kết hợp giữa trường Kind và PK, chỉ số này hoàn toàn là duy nhất, nhưng hãy chờ tôi một chút.
Bây giờ mỗi loại hoặc loại phụ có bảng riêng của nó. Lưu ý rằng mỗi loại quan sát nhận được một bảng, không phải loại dữ liệu.
create table Measurements(
ID int not null,
ObservationKind char( 1 ) check( ObservationKind = 'M' ),
Name varchar( 32 ) not null, -- Such as "CPU Usage"
Value double not null, -- such as 55.00
..., -- other attributes of Measurement observations
constraint PK_Measurements primary key( ID, ObservationKind ),
constraint FK_Measurements_Observations foreign key( ID, ObservationKind )
references Observations( ID, ObservationKind )
);
Hai trường đầu tiên sẽ giống nhau đối với các loại quan sát khác ngoại trừ ràng buộc kiểm tra sẽ buộc giá trị ở loại thích hợp. Các trường khác có thể khác nhau về số lượng, tên và kiểu dữ liệu.
Hãy xem xét một tuple mẫu có thể tồn tại trong bảng Đo lường:
ID ObservationKind Name Value ...
==== =============== ========= =====
1001 M CPU Usage 55.0 ...
Để bộ dữ liệu này tồn tại trong bảng này, trước tiên phải tồn tại một mục phù hợp trong bảng Quan sát với giá trị ID là 1001 và giá trị loại quan sát là 'M'. Không có mục nhập nào khác có giá trị ID là 1001 có thể tồn tại trong bảng Quan sát hoặc bảng Đo lường và hoàn toàn không thể tồn tại trong bất kỳ bảng "loại" nào khác (Sự kiện, Trạng thái). Điều này hoạt động theo cùng một cách cho tất cả các bảng loại.
Tôi cũng khuyên bạn nên tạo một chế độ xem cho từng loại quan sát sẽ cung cấp sự kết hợp của từng loại với bảng quan sát chính:
create view MeasurementObservations as
select ...
from Observations o
join Measurements m
on m.ID = o.ID;
Bất kỳ mã nào chỉ hoạt động với các phép đo sẽ chỉ cần truy cập vào chế độ xem này thay vì các bảng bên dưới. Việc sử dụng các khung nhìn để tạo ra một bức tường trừu tượng giữa mã ứng dụng và dữ liệu thô giúp tăng cường đáng kể khả năng bảo trì của cơ sở dữ liệu.
Giờ đây, việc tạo ra một loại quan sát khác, chẳng hạn như "Lỗi", bao gồm một câu lệnh Chèn đơn giản vào bảng ObservationKinds:
F Fault A fault or error has been detected.
Tất nhiên, bạn cần tạo một bảng và chế độ xem mới cho các quan sát lỗi này, nhưng làm như vậy sẽ không ảnh hưởng đến các bảng, chế độ xem hoặc mã ứng dụng hiện có (tất nhiên là ngoại trừ việc viết mã mới để làm việc với các quan sát mới) .