No he realizado un estudio formal, pero según mi propia experiencia, creo que más del 80 % de las fallas en el diseño de bases de datos se generan al diseñar con el rendimiento como la consideración más importante (si no la única).
Si un buen diseño requiere varias tablas, cree varias tablas. No asuma automáticamente que las uniones son algo que debe evitarse. Rara vez son la verdadera causa de los problemas de rendimiento.
La consideración principal, ante todo en todas las etapas del diseño de la base de datos, es la integridad de los datos. "Es posible que la respuesta no siempre sea correcta, pero podemos dársela muy rápidamente" no es un objetivo por el que cualquier taller deba trabajar. Una vez que se ha bloqueado la integridad de los datos, si el rendimiento alguna vez se convierte en un problema , se puede abordar. No sacrifique la integridad de los datos, especialmente para resolver problemas que pueden no existir.
Con eso en mente, mira lo que necesitas. Tiene observaciones que necesita almacenar. Estas observaciones pueden variar en el número y tipos de atributos y pueden ser cosas como el valor de una medida, la notificación de un evento y el cambio de estado, entre otros y con la posibilidad de que se agreguen observaciones futuras.
Esto parecería encajar en un patrón estándar de "tipo/subtipo", con la entrada "Observación" siendo el tipo y cada tipo o clase de observación siendo el subtipo, y sugiere alguna forma de campo indicador de tipo como:
create table Observations(
...,
ObservationKind char( 1 ) check( ObservationKind in( 'M', 'E', 'S' )),
...
);
Pero codificar una lista como esta en una restricción de verificación tiene un nivel de mantenimiento muy bajo. Se convierte en parte del esquema y solo se puede modificar con sentencias DDL. No es algo que su DBA esperará.
Así que tenga los tipos de observaciones en su propia tabla de búsqueda:
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.
(El campo char bien podría ser int o smallint. Aquí uso char como ilustración).
Luego complete la tabla de Observaciones con un PK y los atributos que serían comunes a todas las observaciones.
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 )
);
Puede parecer extraño crear un índice único en la combinación del campo Tipo y PK, que es único por sí mismo, pero tenga paciencia conmigo un momento.
Ahora cada tipo o subtipo tiene su propia tabla. Tenga en cuenta que cada tipo de observación obtiene una tabla, no el tipo de datos.
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 )
);
Los dos primeros campos serán los mismos para los otros tipos de observaciones, excepto que la restricción de verificación forzará el valor al tipo apropiado. Los demás campos pueden diferir en número, nombre y tipo de datos.
Examinemos una tupla de ejemplo que puede existir en la tabla de medidas:
ID ObservationKind Name Value ...
==== =============== ========= =====
1001 M CPU Usage 55.0 ...
Para que esta tupla exista en esta tabla, primero debe existir una entrada coincidente en la tabla Observaciones con un valor de ID de 1001 y un valor de tipo de observación de 'M'. Ninguna otra entrada con un valor de ID de 1001 puede existir en la tabla de Observaciones o en la tabla de Mediciones y no puede existir en ninguna otra de las tablas de "tipo" (Eventos, Estado). Esto funciona de la misma manera para todas las tablas de tipos.
Recomendaría además crear una vista para cada tipo de observación que proporcione una combinación de cada tipo con la tabla de observación principal:
create view MeasurementObservations as
select ...
from Observations o
join Measurements m
on m.ID = o.ID;
Cualquier código que funcione únicamente con medidas solo necesitaría acceder a esta vista en lugar de a las tablas subyacentes. El uso de vistas para crear un muro de abstracción entre el código de la aplicación y los datos sin procesar mejora en gran medida la capacidad de mantenimiento de la base de datos.
Ahora, la creación de otro tipo de observación, como "Error", implica una simple instrucción Insertar en la tabla ObservationKinds:
F Fault A fault or error has been detected.
Por supuesto, debe crear una nueva tabla y vista para estas observaciones de error, pero hacerlo no tendrá ningún impacto en las tablas, vistas o código de aplicación existentes (excepto, por supuesto, para escribir el nuevo código para trabajar con las nuevas observaciones) .