【问题标题】:Best table structure for tracking state changes跟踪状态变化的最佳表结构
【发布时间】:2014-01-31 17:12:28
【问题描述】:

我目前正在尝试对系统的一个方面进行建模,其中存储的组件可以更改状态,例如 OK、FAILED、REPAIRED 等。在 Web 端,我需要显示当前状态,以及历史以前的(如果有的话)状态。

我在这两种设计之间左右为难,谁能解释一下最好的方法(我更像是一个软件开发人员而不是一个 dba 人)。

选项一:

statehistory table 跟踪每次状态变化,最高序列号将是当前状态:SQLFiddle example

选项二: 与上面类似,除了当前状态存储在组件表中,只有过去的状态存储在历史表中。当状态改变时,当前状态作为历史中最新的状态插入,然后在组件表中设置当前状态:SQLFiddle example

顺便说一句,使用一个或两个但没有状态查找表,只需将状态文本存储为 varchar(我的想法是这样更容易报告吗?):SQLFiddle example

谢谢。

编辑:

有几个组件表,状态历史表应该包含所有这些数据,还是为每个组件制作一个状态历史表?每个组件表都会有数十万个条目,这使得 statehistory 表非常大。

例如: 表:component_a 表:component_b ETC.. 国史( component_a_id, 组件_b_id, state_id, ... )

【问题讨论】:

  • 就个人而言,我会选择 sqlfiddle.com/#!6/f8555 - 但是,我会选择 DATETIME 而不是 int SEQUENCE
  • 序列的日期时间超过 int 的任何具体原因?
  • DATETIME 会比INT 提供更多信息。 DATETIME 将通过MAX 指示最近的(与INT 一样),但它实际上会告诉您何时。再说一次,我的意见。
  • 好点 - 我可能会使用它。我确实打算有一个“状态更改”字段,它是日期时间,我想这会用一块石头杀死两只鸟。

标签: sql sql-server database-design


【解决方案1】:

我倾向于在两者之间进行混合。我总是将所有状态更改(包括当前状态)存储在历史记录表中。这为您提供了一个查询它们的中心位置。您可以拥有一个专栏IsCurrent BIT NOT NULL,让您的生活更轻松。使用过滤器 IsCurrent = 1 创建过滤后的唯一索引以强制执行基本的完整性规则。

我还将当前状态存储在主表中。可能不仅仅是一个副本,而是作为历史表的外键。这使得查询非常方便。查看当前状态通常很有用。当然,出于索引原因,您也可以将值复制到主表中。重复的次数越多,系统就越容易出错。

如果您想避免重复但仍然索引当前状态,您可以创建索引视图来组合主表和历史表。然后,您可以在两个表的混合列上创建索引(例如 on (StatusHistoryItems.Status, Components.Name) 以支持查询具有特定状态和特定名称的客户。此查询将被解析为单个索引搜索在视图的索引上)。

你会创建一个这样的视图:

SELECT *
FROM Components c
JOIN StatusHistoryItems shi on c.ID = shi.ComponentID
     AND c.IsCurrent = 1 --this condition will join exactly one row

并将其编入索引。现在,您在一个有效的索引中拥有当前状态以及所有组件数据。没有重复,根本没有非规范化。只需确保每个客户至少有一个带有IsCurrent = 1 的状态行。

我建议每晚进行一次验证工作,以验证数据一致性并提醒您出现问题。由于各种原因,非规范化数据会随着时间的推移而损坏。

【讨论】:

  • 我喜欢将 fk 从当前组件存储到历史表中的想法 - 我没有想到这一点,谢谢!
  • 感谢您提供如此详细的答案,我会使用您的建议。我在我的原件中添加了一个额外的问题——你对此有什么看法吗?谢谢。
  • 如果逻辑上合适的话,我宁愿合并组件表。 “将有数十万个条目,使 statehistory 表相当大” 不要陷入拆分表的陷阱,希望较小的数据集更快。相反,应用适当的索引和表的大小无关紧要。您必须在性能的祭坛上牺牲数据模型的纯度是非常罕见的。您很可能不在这种情况下。
  • 假设您不希望合并组件表:干净的解决方案是每个组件表一个历史表。这使您可以拥有明显的主键和外键。一个非常标准且易于理解的模式,具有很强的强制完整性。我只会有充分的理由偏离该模型。你觉得有吗?
  • 我无法合并组件表,因为它不适合。我担心的是,它们都有一个历史表,然后在组件中添加一个 fk,对于历史表中的每一行,都会有一个填充的 fk 字段,然后是 x 个空值。您对数据大小的看法是正确的,我对索引设计还很陌生,所以我认为我需要认真阅读以确保良好的性能。
猜你喜欢
  • 2021-12-12
  • 1970-01-01
  • 1970-01-01
  • 2011-01-09
  • 2023-04-08
  • 1970-01-01
  • 2021-09-04
  • 2017-09-07
  • 2011-02-06
相关资源
最近更新 更多