コメントを格納するテーブルがあります。コメントは、別のユーザーからのものか、このアプリの個別のエンティティである別のプロファイルからのものである可能性があります。
私の当初の考えでは、テーブルにはuser_idフィールドとprofile_idフィールドの両方があるため、ユーザーがコメントを送信すると、user_idはprofile_idを空白のままにします。
これは正しいですか、間違っていますか、もっと良い方法はありますか?
コメントを格納するテーブルがあります。コメントは、別のユーザーからのものか、このアプリの個別のエンティティである別のプロファイルからのものである可能性があります。
私の当初の考えでは、テーブルにはuser_idフィールドとprofile_idフィールドの両方があるため、ユーザーがコメントを送信すると、user_idはprofile_idを空白のままにします。
これは正しいですか、間違っていますか、もっと良い方法はありますか?
最善の解決策は、IMHOがテーブルだけでなく、アプリケーションの他の場所でどのように使用されるかに依存します。
コメントがすべて他のオブジェクトに関連付けられていると仮定して、そのオブジェクトからすべてのコメントを抽出するとします。提案された設計では、すべてのコメントを抽出するには、1つのテーブルから選択する必要があります。これは効率的です。しかし、それは各コメントの投稿者に関する情報を抽出せずにコメントを抽出することです。表示したくない場合や、すでにメモリにキャッシュされている場合があります。
しかし、コメントを取得しているときに投稿者に関する情報を取得する必要がある場合はどうでしょうか。次に、2つの異なるテーブルを結合する必要があります。これで、結果のレコードセットが多くのNULL値で汚染されます(プロファイルコメントの場合、すべてのユーザーフィールドがNULLになります)。この結果セットを解析する必要があるコードも、より複雑になる可能性があります。
個人的には、完全に正規化されたバージョンから始めて、パフォーマンスの問題が発生し始めたら非正規化するでしょう。
この問題にはまったく異なる解決策もありますが、これはドメインで意味があるかどうかによって異なります。アプリケーション内に、ユーザーとポスターを同じように使用できる場所が他にある場合はどうなりますか?ユーザーが特別な種類のプロファイルである場合はどうなりますか?次に、ソリューションは一般的にユーザー/プロファイルテーブルで解決する必要があると思います。例(一部の省略形の疑似SQL):
create table AbstractProfile (ID primary key, type ) -- type can be 'user' or 'profile'
create table User(ProfileID primary key references AbstractProfile , ...)
create table Profile(ProfileID primary key references AbstractProfile , ...)
次に、ユーザーまたはプロファイルを交換可能に使用できるアプリケーション内の任意の場所で、LoginIDを参照できます。
コメントが複数のオブジェクトに対して一般的である場合は、オブジェクトごとにテーブルを作成できます。
user_comments (user_id, comment_id)
profile_comments (profile_id, comment_id)
そうすれば、コメントテーブルに空の列を含める必要はありません。また、コメントテーブルに触れることなく、将来的に新しいcomment-source-objectsを簡単に追加できるようになります。
解決する別の方法は、コメントのコメント投稿者の名前を常に非正規化(コピー)し、タイプとIDフィールドを介してコメント投稿者への参照を保存することです。そうすれば、統一されたコメントテーブルが作成され、検索、並べ替え、トリミングをすばやく行うことができます。欠点は、コメントとその所有者の間に実際のFK関係がないことです。
以前、私は一元化されたコメントテーブルを使用し、それが参照しているfk_tableのフィールドを持っていました。
例えば:
comments(id,fk_id,fk_table,comment_text)
このようにして、UNIONクエリを使用して、複数のソースからのデータを連結できます。
SELECT c.comment_text FROM comment c JOIN user u ON u.id=c.fk_id WHERE c.fk_table="user"
UNION ALL
SELECT c.comment_text FROM comment c JOIN profile p ON p.id=c.fk_id WHERE c.fk_table="profile"
これにより、冗長なテーブルを作成せずに、コメントを持つオブジェクトの数を増やすことができます。
これは、外部キーを介して参照整合性を維持し、一元管理し、インデックスなどの標準データベースツールを使用して最高のパフォーマンスを提供し、本当に必要な場合はパーティション分割などを可能にする別のアプローチです。
create table actor_master_table(
type char(1) not null, /* e.g. 'u' or 'p' for user / profile */
id varchar(20) not null, /* e.g. 'someuser' or 'someprofile' */
primary key(type, id)
);
create table user(
type char(1) not null,
id varchar(20) not null,
...
check (id = 'u'),
foreign key (type, id) references actor_master_table(type, id)
);
create table profile(
type char(1) not null,
id varchar(20) not null,
...
check (id = 'p'),
foreign key (type, id) references actor_master_table(type, id)
);
create table comment(
creator_type char(1) not null,
creator_id varchar(20) not null,
comment text not null,
foreign key(creator_type, creator_id) references actor_master_table(type, id)
);