私は正式な調査を行っていませんが、私自身の経験から、データベース設計の欠陥の80%以上は、パフォーマンスを(それだけではないにしても)最も重要な考慮事項として設計することから発生していると思います。
優れた設計で複数のテーブルが必要な場合は、複数のテーブルを作成します。結合が避けるべきものであると自動的に想定しないでください。これらがパフォーマンスの問題の真の原因になることはめったにありません。
データベース設計のすべての段階で最も重要な考慮事項は、データの整合性です。 「答えは必ずしも正しいとは限りませんが、すぐに答えることができます」というのは、どのショップも目指すべき目標ではありません。データの整合性がロックダウンされた後、パフォーマンスが問題になる場合 、対処できます。特に存在しない可能性のある問題を解決するために、データの整合性を犠牲にしないでください。
それを念頭に置いて、必要なものを見てください。保存する必要のある観測値があります。これらの観測値は、属性の数と種類が異なる可能性があり、測定値、イベントの通知、ステータスの変更など、将来の観測値が追加される可能性があるものなどがあります。
これは、標準の「タイプ/サブタイプ」パターンに適合しているように見えます。「Observation」エントリはタイプであり、各タイプまたは種類のオブザベーションはサブタイプであり、次のような何らかの形式のタイプインジケータフィールドを提案します。
create table Observations(
...,
ObservationKind char( 1 ) check( ObservationKind in( 'M', 'E', 'S' )),
...
);
ただし、このようなリストをチェック制約にハードコーディングすると、保守性レベルが非常に低くなります。これはスキーマの一部になり、DDLステートメントでのみ変更できます。 DBAが楽しみにしていることではありません。
したがって、独自のルックアップテーブルにある種の観測値があります:
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.
(charフィールドはintまたはsmallintでもかまいません。ここでは説明のためにcharを使用しています。)
次に、観測テーブルにPKとすべての観測に共通する属性を入力します。
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 )
);
KindフィールドとPKの組み合わせで一意のインデックスを作成するのは奇妙に思えるかもしれませんが、それ自体は一意ですが、しばらくお待ちください。
これで、各種類またはサブタイプが独自のテーブルを取得します。各種類の観測値は、データ型ではなくテーブルを取得することに注意してください。
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 )
);
最初の2つのフィールドは、チェック制約が値を適切な種類に強制することを除いて、他の種類の観測値でも同じです。他のフィールドは、数、名前、データ型が異なる場合があります。
Measurementsテーブルに存在する可能性のあるタプルの例を調べてみましょう:
ID ObservationKind Name Value ...
==== =============== ========= =====
1001 M CPU Usage 55.0 ...
このタプルがこのテーブルに存在するためには、最初に、ID値が1001でオブザベーションの種類の値が「M」の一致するエントリがオブザベーションテーブルに存在する必要があります。 ID値が1001の他のエントリは、ObservationsテーブルまたはMeasurementsテーブルのいずれにも存在できず、他の「種類」テーブル(イベント、ステータス)にはまったく存在できません。これは、すべての種類のテーブルで同じように機能します。
さらに、各種類の観測のビューを作成して、各種類のメインの観測テーブルとの結合を提供することをお勧めします。
create view MeasurementObservations as
select ...
from Observations o
join Measurements m
on m.ID = o.ID;
測定値のみで機能するコードは、基になるテーブルではなく、このビューにのみヒットする必要があります。ビューを使用して、アプリケーションコードと生データの間に抽象化の壁を作成すると、データベースの保守性が大幅に向上します。
ここで、「エラー」などの別の種類の観測の作成には、ObservationKindsテーブルへの単純なInsertステートメントが含まれます。
F Fault A fault or error has been detected.
もちろん、これらのエラーオブザベーション用に新しいテーブルとビューを作成する必要がありますが、そうしても既存のテーブル、ビュー、またはアプリケーションコードに影響はありません(もちろん、新しいオブザベーションで機能する新しいコードを作成する場合を除く)。 。