28

エンティティ属性値 (EAV) アプローチを使用して、患者/サンプル メタデータ テーブルを作成したいと考えています。

質問:属性に基づいて、のさまざまな列タイプ (文字列、数値、または辞書テーブルへの外部キーなど) をどのように処理すればよいですか?

注: EAV アプローチを使用するかどうかを尋ねているわけではありません。私は他のSOの質問参照を見て、これが私のユースケースに最適なアプローチであると信じています(たとえば、属性ごとに個別の列またはテーブルを作成したくない-数百に及ぶ可能性があります)。ただし、包括的な例を示して、他の設計を再考することは確かです。

代表的なデータ

患者/サンプル (エンティティ) は、複数のメタデータ属性(検査室の場所、生存率、腫瘍の種類など) を持つことができ、それぞれに異なる値の種類 (それぞれ 、*などVARCHAR)があります。NUMBERFOREIGN_KEY

*FOREIGN_KEYは、この値の型が、INTEGERの辞書テーブルへの外部キー ID ( ) であることを意味します(例: 10 の可能な腫瘍型のリスト)。これらの値を正規化することは気にしないので、ラボの場所は可能です。しかし、腫瘍の種類にはある程度の検証が必要です。VARCHAR

私のテーブルレイアウトは次のようになります。

CREATE TABLE patients (
  patient_id INTEGER CONSTRAINT pk_patients PRIMARY KEY,
  patient_name VARCHAR2(50) NOT NULL
);

CREATE TABLE metadata_attributes (
  attribute_id INTEGER CONSTRAINT pk_metadata_attributes PRIMARY KEY,
  attribute_name VARCHAR2(50) NOT NULL,
  attribute_value_type VARCHAR(50) NOT NULL -- e.g. VARCHAR, NUMBER, or ID
);

CREATE TABLE patient_metadata (
  patient_id CONSTRAINT fk_pm_patients REFERENCES patients(patient_id) NOT NULL,
  attribute_id CONSTRAINT fk_pm_attributes REFERENCES metadata_attributes(attribute_id) NOT NULL,
  attribute_value ???
);

参照する列/テーブルを知るには、metadata_attributes テーブルにの型を識別する列 (attribute_value_type)が必要だと思います。

可能なアプローチ

ここに私が考えることができる2つの可能なアプローチがあります。

アプローチ 1: 複数の列を持つ単一の EAV テーブル

の種類ごとに 1 つずつ、patient_metadata テーブルに 3 つの異なる列を作成します。

CREATE TABLE patient_metadata (
  patient_id CONSTRAINT fk_pm_patients REFERENCES patients(patient_id) NOT NULL,
  attribute_id CONSTRAINT fk_pm_attributes REFERENCES metadata_attributes(attribute_id) NOT NULL,
  attribute_varchar_value VARCHAR(50),
  attribute_number_value NUMBER,
  attribute_id_value CONSTRAINT fk_pm_values REFERENCES some_table_of_values(value_id)
);

アプローチ 2: 複数の EAV テーブル

のタイプごとに 1 つずつ、3 つの異なる Patient_metadata テーブルを作成します。

CREATE TABLE patient_metadata_varchar (
  patient_id CONSTRAINT fk_pm_patients REFERENCES patients(patient_id) NOT NULL,
  attribute_id CONSTRAINT fk_pm_attributes REFERENCES metadata_attributes(attribute_id) NOT NULL,
  attribute_value VARCHAR(50) NOT NULL
);

CREATE TABLE patient_metadata_number (
  patient_id CONSTRAINT fk_pm_patients REFERENCES patients(patient_id) NOT NULL,
  attribute_id CONSTRAINT fk_pm_attributes REFERENCES metadata_attributes(attribute_id) NOT NULL,
  attribute_value NUMBER NOT NULL
);

CREATE TABLE patient_metadata_id (
  patient_id CONSTRAINT fk_pm_patients REFERENCES patients(patient_id) NOT NULL,
  attribute_id CONSTRAINT fk_pm_attributes REFERENCES metadata_attributes(attribute_id) NOT NULL,
  attribute_value CONSTRAINT fk_pm_values REFERENCES some_table_of_values(value_id) NOT NULL
);

他のアプローチ?

そこに他のアプローチはありますか?

つまり、リレーショナル整合性を可能な限り尊重し、データベースがの型を認識できるようにして、基本的な検証を実行できるようにしたいと考えています。ただし、上記の両方のアプローチでは、何らかの種類の手動の整合性チェックが必要になると思います (アプローチ 1 では、1 つの attribute_value 列のみが入力されていることを確認する必要があるなど)。

実行するクエリの種類は一般的です (たとえば、特定のメタデータ属性ののリストを取得する、特定の患者 (エンティティ) およびメタデータ属性ののリストを取得するなど)。照会する列またはテーブルを知るために、ほとんどの場合、の型を照会する必要があると思います。これを回避する他の方法はありますか?

すべてのアプローチ (パフォーマンス、クエリ構造など) の長所と短所は何ですか?

初めてのポスターですので、事前に感謝し、フォーマットやさらなる明確化についてお気軽にコメントしてください!

4

2 に答える 2

4

最も簡単で最もパフォーマンスの高い方法は、データベース内のすべての値を文字列に変換することです。示されているような問題は通常明らかであり、適切に型付けされた列でさえ、まったく同じ種類の問題を抱えており、通常はパフォーマンスの問題として表されます。

多少の注意を払えば、照合順序が重要な場合は維持できます (たとえば、日付を年/月/日としてフォーマットすることにより)。いずれにせよ、遅すぎるため、型の検証をデータベースで行うべきではありません。負の数は浮動小数点数と同様に厄介ですが、負数または浮動小数点数になる可能性のある数値でインデックスを作成することは非常にまれであり、メモリ内の並べ替えは一般的に高速です。

データの型が明らかでない場合、または下流のプロセッサに知らせる必要がある場合は、型の列を追加します。

一般に、列の値に対するすべての整合性制約は、レコードが書き込まれる前に、コード (良い) またはトリガー (あまり良くない) のいずれかでチェックできます。さまざまな型でネイティブ機能を使用しようとしても、これまでのところしか取得できません。また、生年月日は null 以外で 1900 年以降である必要があるなど、値には多くのビジネス固有の制約があることが多いため、おそらくあまり役​​に立ちません。

パフォーマンスのために、エンティティと属性をプレフィックスとして含む複合インデックスを使用します。インデックスはエンティティ属性プレフィックスによってパーティション化されるため、インデックスの余分な深さの影響が軽減され、非常によく圧縮されます (プレフィックスは 1 バイトまたは 2 バイトに圧縮されます)。そのため、サイズの違いは最小限に抑えられます。

EAV テーブルからのクエリは、多くの場合、エンティティをアンパックするビューで行うのが最適です。これにより、期待どおりの構造に戻すことができます。歴史に応じてさまざまな要素が多数含まれています。そうすれば、ビジネスロジックで処理する方がおそらく簡単です。

最後に、今日、この種のデータは、列指向のリレーショナル データベース スタイルで格納されていません。これは通常、XML (または JSON) ドキュメント (Oracle では XML タイプ) として保存され、ほとんどのデータベースは、そのようなデータを検索および操作するためにネイティブ XML 処理機能を提供します。これは、通常のフォームの保存と取得には問題ありませんが、「昨年肺炎にかかった 60 歳以上のすべての患者を教えてください」などの任意のクエリを作成する傾向があり、タグ付けされた逆インデックスが必要なため、やや複雑になる傾向があります。それにもかかわらず、ドキュメント指向/テキスト指向のアプローチがより優れたソリューションであるかどうかを確認する価値があります。

幸運を!

于 2013-09-04T15:54:41.513 に答える