我应该将所有MySQL表相互关联吗?

时间:2011-12-03 04:38:47

标签: mysql sql database-design

我正在开展个人项目,以便对各种项目进行计时,但我不确定构建数据库的最佳方法。

结构的简化细分如下:

  • 每个客户都可以有多个报告。
  • 每个报告可以包含多个订单项。
  • 每个订单项可以包含多个时间记录。

最终会有更多关系,但这是应用程序的基础。如您所见,每个项目都与一对多关系中的项目相关。

我的问题是,我应该将每个表与上面的每个“父”表相关联吗?像这样:

clients
    id

reports
    id
    client_id

line_items
    id
    report_id
    client_id

time_records
    id
    report_id
    line_item_id
    client_id

随着它逐渐减少,每个新表中会添加越来越多的外键。

我最初的反应是,这不是正确的做法,但我希望得到一些第二(和第三!)意见。

5 个答案:

答案 0 :(得分:3)

您执行此操作的方式的优点是您可以检查所有时间记录,例如,特定客户端ID,而无需连接。但实际上,没有必要。您所需要的只是存储一个“级别”的引用,可以这么说。以下是“客户”视角的一些示例:

获取特定客户的报告(简单;与您建议的当前架构相同)

SELECT * FROM `reports`
    WHERE `client_id` = ?;

获取特定客户的订单项:(新架构;表格中不需要“client_id”)

SELECT `line_items`.* FROM `line_items`
    JOIN `reports` ON `reports`.`id` = `line_items`.`id`
    JOIN `clients` ON `clients`.`id` = `reports`.`client_id`
    WHERE `clients`.`id` = ?;

获取特定客户的时间条目:(新架构;表格中不需要“client_id”或“report_id”)

SELECT `time_records`.* FROM `time_records`
    JOIN `line_items` ON `line_items`.`id` = `time_records`.`line_item_id`
    JOIN `reports` ON `reports`.`id` = `line_items`.`id`
    JOIN `clients` ON `clients`.`id` = `reports`.`client_id`
    WHERE `client_id` = ?;

因此,修订后的架构将是:

clients
    id

reports
    id
    client_id

line_items
    id
    report_id

time_records
    id
    line_item_id

修改

此外,我会考虑使用视图来简化查询(我假设你经常使用它们),肯定在连接列上创建索引,并利用外键引用进行规范化(仅限InnoDB)。

答案 1 :(得分:1)

不,如果模型的元素没有直接关系,那么在相应的表中不应该有直接的关系。否则,您的数据将有冗余,您将无法进行更新。

这是正确的方法:

clients
    id

reports
    id
    client_id

line_items
    id
    report_id

time_records
    id
    line_id

答案 2 :(得分:1)

如果您从未直接将订单项直接加入客户,则无需在client_id表格上创建line_items,因为您可以通过reports表格获取该订单项。其他FK也是如此。

我建议您在创建可能使开发复杂化的冗余外键之前,在报表中考虑对此数据集的需求/查询。

如果您将来需要它们,创建冗余FK并不困难,一些ALTERS和UPDATE SELECTS可以解决您的问题。

如果您在line_items中没有太多信息,可以在time_records中进行非规范化并添加此信息。

答案 3 :(得分:1)

在两个表之间存在直接关系的任何地方,您应该使用外键来保持数据的完整性。就个人而言,我会看一下这样的结构:

Client
    ClientId

Report
    ReportId
    ClientId

LineItem
    LineItemId
    ReportId

TimeRecord
    TimeRecordId
    LineItemId

在此示例中,ClientId中不需要LineItem,因为您通过Report表拥有该关系。在所有表中使用ClientId的主要缺点是,如果业务逻辑不强制执行这些值的一致性(代码中存在错误),则可以遇到如果基于搜索而获得不同值的情况上

Report:
   ReportId = 3
   ClientId = 2
LineItem:
   LineItemId = 1
   ReportId = 3
   ClientId = 3

在上述情况下,如果您的查询经历了ClientId = 2Report,如果您的查询通过ClientId = 3,那么您会看LineItem这一切很难发生确定哪个关系是正确的,以及错误的位置。

另外,我主张不使用id列,而是使用更明确的名称来描述id的用途。 (ReportIdClientId)在我看来,这使得联接更容易阅读。举个例子:

SELECT COUNT(1) AS NumberOfLineItems
FROM Client AS c
INNER JOIN Report AS r ON c.ClientId = r.ClientId
INNER JOIN LineItem AS li ON r.ReportId = li.ReportId
WHERE c.ClientId = 12

答案 4 :(得分:0)

作为个人意见,我会:

clients
    id

time_records
    id
    client_id
    report
    line_item
    report_id

这样你的所有字段都在time_records表中。然后你可以做类似的事情:

SELECT *
FROM 'time_records'
WHERE 'time_records'.'client_id' = 16542
   AND 'time_records'.'report' = 164652
ORDER BY 'time_records'.'id' ASC