web-dev-qa-db-ja.com

1つの汎用マッピングテーブルと多くの特定のマッピングテーブル

エンドユーザーがアップロードしたファイルを追跡するデータベーステーブルを設計しようとしています。
ファイルはさまざまなコンテキストでアップロードできます。
各コンテキストは異なるテーブルです。

例として:

  • 従業員は、「毎週の経費」エントリに対して複数の「領収書」ファイルをアップロードできます。
  • 従業員は、「ペット」エントリに対して複数の「写真」ファイルをアップロードできます。

この(不自然な)シナリオのエンティティ/テーブルは次のとおりです。

  • Employees (Id, Name)
  • Expenses (Id, Date, RequestedRefund, RequestedByEmployeeId)
  • Pets (Id, Name, Type, BelongsToEmployeeId)

ファイル自体に関する情報を追跡するFilesというテーブルがすでにあります。
Files (Id, Name, Size, Extension, Folder)

私の質問は、経費領収書のアップロードとペットの写真のアップロードをファイルレコードに対してどのようにマッピングするかです。私はこれを2つの方法で実行できることを知っています。

最初のオプション:

汎用マッピングテーブルを1つ用意します:GenericFileMap (FileId, ContextId, Type)
どこ

  • FileIdはファイルレコードのIDです
  • ContextIdは、取得しようとしているコンテキストレコードのIDです。
  • Typeは、コンテキスト自体を説明するフィールドです

このシナリオでは、従業員のすべての経費領収書を次のように取得します。

_SELECT *
FROM Employee e
INNER JOIN Expenses ex ON e.Id = ex.RequestedByEmployeeId
INNER JOIN GenericFileMap g ON g.ContextId = ex.Id AND g.Type = 'expense'
INNER JOIN Files f ON g.FileId = f.Id
_

2番目のオプション:

エンティティ/コンテキストテーブルごとに個別のマッピングテーブルを用意します。

  • ExpenseFiles (ExpenseId, FileId)
  • PetFiles (PetId, FileId)

領収書のクエリは次のようになります。

_SELECT *
FROM Employee e
INNER JOIN Expenses ex ON e.Id = ex.RequestedByEmployeeId
INNER JOIN ExpenseFiles ef ON ef.ExpenseId = ex.Id
INNER JOIN Files f ON ef.FileId = f.Id
_

最初のオプションは、リレーショナルデータベースで処理を行う「正規化された」方法ではないと思います。しかし、これを検討している唯一の理由は、私の特定の状況では、ユーザーがファイルをアップロード/添付できる少なくとも15の異なるコンテキストがあることです。

最初のオプションから私が見る唯一の利点は、すべてのコンテキストごとにテーブルとストアドプロシージャ(CRUDに1つずつ)を作成および複製する時間を節約できることです。

ただし、2番目のオプションは、物事を行う「正しい」方法であると思われます。

私の質問:

  1. 2つのオプションのどちらがよりスマートなアプローチですか?
  2. 2つのうちどちらが長い目で見てパフォーマンスに優れていますか(2番目のオプションのパフォーマンスが向上する場合は、必要な追加の労力を費やします)。
4
Jason

次の理由により、オプション#1は必要ありません。

  1. ContextIdTypeFilesテーブルに配置することもできます。
  2. _TypeID TINYINT_フィールド(および関連するTypeルックアップテーブル)を使用すると、毎回非効率的な文字列比較を行う必要がなくなります。

おそらく最善の方法は、変更されたオプション#2です。はい、コンテキスト固有のファイルマップテーブル(たとえば、ExpenseFilesPetFilesなど)から始めますが、_ContextTypeID TINYINT_列も追加します既存のFilesテーブル内。また、_ContextTypeID TINYINT NOT NULL_を主キーとする新しいContextTypeルックアップテーブルも必要です(ただし、notにしてIDENTITY列にします)。 Name列をルックアップテーブルに追加し、FilesからContextTypeへの外部キーをContextTypeIDに追加できます。 Filesテーブルにこの新しい列があると、関連するレコードがどのコンテキスト固有のファイルマップ/プロパティテーブルにあるかを簡単に判断できます。

オプション#2を使用する理由は、15の異なるコンテキストがある場合でも、必然的に、少なくともそれらの一部は時間の経過とともに進化および分岐するためです。だからあなたは持っているかもしれません:

  • ExpenseFiles (ExpenseId, FileId, Date, Total)
  • PetFiles (PetId, FileId, Name, Age, AnimalType)
2
Solomon Rutzky