用于跟踪状态变化的最佳表结构

时间:2014-01-31 08:55:08

标签: sql sql-server database-design

我正在尝试建模一个系统的一个方面,其中存储的组件可以改变状态,例如OK,FAILED,REPAIRED等。在网络方面,我将需要显示当前状态,但也需要显示以前(如果有的话)。

我在这两个设计之间徘徊,任何人都可以对最好的方式有所了解(我更像是一个软件开发者而不是dba家伙。)

选项一:

状态历史表,跟踪每次状态变化时,最高序列号将是当前状态:SQLFiddle example

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

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

感谢。

修改

有几个组件表,状态历史表是否包含所有这些组件的数据,或者每个组件创建一个状态历史表?每个组件表都有数十万个条目,使状态历史表非常大。

例如:  表:component_a  表:component_b  等等..  statehistory(  component_a_id,  component_b_id,  STATE_ID,  ...  )

1 个答案:

答案 0 :(得分:1)

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

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

如果要避免重复但仍然对当前状态建立索引,则可以创建索引视图以组合主表和历史表。然后,您可以在两个表的混合列上创建索引(例如,在(StatusHistoryItems.StatusComponents.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至少有一个状态行。

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