Jag har inte gjort en formell studie, men av min egen erfarenhet skulle jag gissa att mer än 80 % av databasdesignbristerna genereras från design med prestanda som det viktigaste (om inte bara) övervägandet.
Om en bra design kräver flera tabeller, skapa flera tabeller. Anta inte automatiskt att anslutningar är något som bör undvikas. De är sällan den verkliga orsaken till prestandaproblem.
Det primära övervägandet, först och främst i alla stadier av databasdesign, är dataintegritet. "Svaret kanske inte alltid är korrekt, men vi kan få det till dig väldigt snabbt" är inte ett mål någon butik bör arbeta mot. När dataintegriteten har låsts, om prestanda någonsin blir ett problem , det kan åtgärdas. Offra inte dataintegritet, särskilt för att lösa problem som kanske inte finns.
Med det i åtanke, titta på vad du behöver. Du har observationer som du behöver lagra. Dessa observationer kan variera i antal och typer av attribut och kan vara saker som värdet av en mätning, meddelande om en händelse och förändring av en status, bland annat och med möjligheten att framtida observationer läggs till.
Detta verkar passa in i ett standardmönster för "typ/undertyp", där posten "Observation" är typen och varje typ eller typ av observation är undertypen, och föreslår någon form av typindikatorfält som:
create table Observations(
...,
ObservationKind char( 1 ) check( ObservationKind in( 'M', 'E', 'S' )),
...
);
Men hårdkodning av en lista som denna i en kontrollbegränsning har en mycket låg underhållsnivå. Det blir en del av schemat och kan endast ändras med DDL-satser. Inget din DBA kommer att se fram emot.
Så har de typer av observationer i sin egen uppslagstabell:
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.
(Rädefältet kan lika gärna vara int eller smallint. Jag använder röd här för att illustrera.)
Fyll sedan i observationstabellen med en PK och de attribut som skulle vara gemensamma för alla observationer.
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 )
);
Det kan tyckas konstigt att skapa ett unikt index över kombinationen av Kind field och PK, som är unikt i sig, men håll ut med mig ett ögonblick.
Nu får varje typ eller undertyp sin egen tabell. Observera att varje typ av observation får en tabell, inte datatypen.
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 )
);
De två första fälten kommer att vara desamma för de andra typerna av observationer, förutom att kontrollbegränsningen tvingar värdet till lämplig typ. De andra fälten kan skilja sig åt i antal, namn och datatyp.
Låt oss undersöka ett exempel som kan finnas i tabellen Mått:
ID ObservationKind Name Value ...
==== =============== ========= =====
1001 M CPU Usage 55.0 ...
För att denna tuppel ska finnas i den här tabellen måste det först finnas en matchande post i observationstabellen med ett ID-värde på 1001 och ett observationstypvärde på 'M'. Ingen annan post med ett ID-värde på 1001 kan finnas i varken observationstabellen eller tabellen Mätningar och kan inte existera alls i någon annan av de "snälla" tabellerna (händelser, status). Detta fungerar på samma sätt för alla snälla bord.
Jag skulle vidare rekommendera att skapa en vy för varje typ av observation som ger en koppling av varje typ till huvudobservationstabellen:
create view MeasurementObservations as
select ...
from Observations o
join Measurements m
on m.ID = o.ID;
Varje kod som enbart fungerar med mätningar skulle behöva bara träffa den här vyn istället för de underliggande tabellerna. Att använda vyer för att skapa en vägg av abstraktion mellan applikationskoden och rådata förbättrar avsevärt databasens underhållbarhet.
Nu innebär skapandet av en annan typ av observation, såsom "Error", en enkel Insert-sats i tabellen ObservationKinds:
F Fault A fault or error has been detected.
Naturligtvis måste du skapa en ny tabell och vy för dessa felobservationer, men att göra det kommer inte att påverka befintliga tabeller, vyer eller applikationskod (förutom, naturligtvis, att skriva den nya koden för att fungera med de nya observationerna) .