一个通用映射表 VS 许多特定映射表

Jas*_*son 5 database-design sql-server table

我正在尝试设计数据库表来跟踪最终用户上传的文件。
文件可以在不同的上下文中上传。
每个上下文都是一个不同的表。

举个例子:

  • 员工可以针对“每周费用”条目上传多个“收据”文件。
  • 员工可以针对“宠物”条目上传多个“照片”文件。

这个(人为的)场景中的实体/表是:

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

我已经有一个名为的表Files,用于跟踪有关文件本身的信息:
Files (Id, Name, Size, Extension, Folder)

我的问题是关于如何根据文件记录映射费用收据上传和宠物照片上传。我知道我可以通过两种方式做到这一点:

第一个选项:

有一个通用映射表:GenericFileMap (FileId, ContextId, Type)
where

  • 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
Run Code Online (Sandbox Code Playgroud)

第二个选项:

每个实体/上下文表都有单独的映射表:

  • 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
Run Code Online (Sandbox Code Playgroud)

我相信第一个选项不是在关系数据库中做事的“规范化”方式。但我考虑这一点的唯一原因是,在我的特定情况下,用户可以上传/附加文件至少有 15 种不同的上下文。

我从第一个选项中看到的唯一好处是我为每个上下文节省了创建和复制表和存储过程(每个用于 CRUD)的时间。

然而,似乎第二种选择是做事的“正确”方式。

我的问题:

  1. 这两个选项中哪一个是更聪明的方法?
  2. 从长远来看,两者中哪一个对性能更好(如果第二个选项的性能更高,我肯定会付出额外的努力)?

Sol*_*zky 2

您不需要选项#1,因为:

  1. 您不妨将ContextIdType放入桌子中Files
  2. 您最好使用TypeID TINYINT字段(以及关联的Type查找表),这样您就不需要每次都进行低效的字符串比较。

最好的可能是修改选项#2。是的,从特定于上下文的文件映射表(例如,,等)开始,ExpenseFilesPetFiles也要ContextTypeID TINYINT在现有Files表中添加一列。还应该有一个新的ContextType查找表ContextTypeID TINYINT NOT NULL作为主键(但不要其设为IDENTITY列)。您可以Name向查找表添加一列,并添加一个外键 fromFilesContextTypeon ContextTypeID。在表中添加这个新列Files将使您更容易确定关联记录位于哪个上下文特定的文件映射/属性表中。

即使存在 15 种不同的环境,选择选项 2 的原因是,不可避免地,至少其中一些会随着时间的推移而演变和分歧。所以你可能有:

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