数据库“supertable”vs更多表vs泛型表

时间:2010-11-29 17:11:58

标签: database database-design database-normalization

我正在尝试决定数据库设计。更具体地说,这是较大设计的子部分。基本上,有“位置” - 每个位置可以有任意数量的传感器,它可以有一个记录器(但只有1个)。

我有传感器读数,并且我有记录器读数,每个都不同,我认为需要单独的表格。

如果传感器读数超出范围,则会生成警报。当传感器读数超出范围时,它们会与该警报保持关联,因此您最终得到包含许多读数的1个警报,以便我稍后绘制警报图,以便我可以发现趋势等。

与记录器读数相同。

以下是我目前存储这些数据的3个想法:

选项1:

Location [Table]
- Id [PK]
- Name
- HasLogger

LiveSensor [Table]
- LocationId [FK]
- Id [PK]

LiveSensorReading [Table]
- Id [PK]
- SensorId [FK]
- Value

LiveSensorAlert [Table]
- Id [PK]
- SensorReadingId [FK] (may not be needed - enforces need to always have at least 1 reading)

LiveSensorAlertCorrectiveAction [Table]
- LiveSensorAlertId [FK]
- CorrectiveActionId [FK]
- ByUserId [FK]

LiveSensorAlertAcknowledgement [Table]
- LiveSensorAlertId [FK]
- ByUserID [FK]

LiveSensorAlertReading [Table]
- SensorAlertId [FK]
- SensorReadingId [FK]

LoggerReading [Table]
- LocationId [FK]
- Value

LoggerAlert [Table]
- Id [PK]
- LoggerReadingId [FK] (may not be needed - enforces need to always have at least 1 reading)

LoggerAlertReading [Table]
- LoggerAlertId [FK]
- LoggerReadingId [FK]

LoggerAlertCorrectiveAction [Table]
- LoggerAlertId [FK]
- CorrectiveActionId [FK]
- ByUserId [FK]

LoggerAlertAcknowledgement [Table]
 - LoggerAlertId [FK]
 - ByUserID [FK]
  • 问题:很多重复的表(这真的很重要吗??)

选项2:

Location [Table]
- Id
- Name
- HasLogger

Sensor [Table]
- Id [PK]
- LocationId [FK]

SensorReading [Table]
- Id [PK]
- SensorId [FK]
- Value

LoggerReading
- LocationId [FK]
- Value

Alert [Table]
- Id [PK]

AlertCorrectiveAction [Table]
- AlertId [FK]
- CorrectiveActionId [FK]
- ByUserId [FK]

AlertAcknowledgement [Table]
- AlertId [FK]
- ByUserId [FK]

SensorAlertReading
- AlertId [FK]
- SensorReadingId [FK]

LoggerAlertReading
 - AlertId [FK]
 - LoggerReadingId [FK]
  • 问题:不执行“至少1” 每次提醒阅读“规则。
  • 问题:允许多种类型的 阅读以引用相同的警报。

选项3:

Location [Table]
- Id
- Name
- HasLogger

Sensor [Table]
- Id [PK]
- LocationId [FK]

SensorReading [Table]
- Id [PK]
- SensorId [FK]
- Value

LoggerReading
- LocationId [FK]
- Value

Alert [Table] "super table"
- Id [PK]

LoggerAlert [Table]
- AlertId [PK, FK]
- LoggerReadingId [FK]

SensorAlert [Table]
- AlertId [PK, FK]
- SensorReadingId [FK]

AlertCorrectiveAction [Table]
- AlertId [FK]
- CorrectiveActionId [FK]
- ByUserId [FK]

AlertAcknowledgement [Table]
- AlertId [FK]
- ByUserId [FK]

SensorAlertReading [Table]
- SensorAlertId [FK]
- SensorReadingId [FK]

LoggerAlertReading [Table]
 - LoggerAlertId [FK]
 - LoggerReadingId [FK]
  • 问题:什么都没有停止 LoggerAlert和SensorAlert 引用相同的警报(同样的问题 作为选项2)。
  • 问题:混淆数据库(不是 超级表更多的OO概念?一个 数据库本质上是纯粹的 关系不是吗?)

我认为到目前为止我更喜欢选项1因为它看起来很干净而且意图很明确(我希望!),即使我正在有效地重复表格。

我刚才想到的唯一一个小问题是,不同传感器的读数仍然可以与一个警报相关联。

我想知道人们对上述选项的意见。我已经看到经常使用“超级表”安静,但由于某种原因它只是感觉不对 - 它几乎感觉有点像黑客,特别是当我看到试图确保数据完整性的方法时。它看起来比OO编程更像是关系设计。

感谢。

修改 一些进一步的信息,以帮助回答以下一些问题:

大多数情况下,数据库只能通过应用程序服务器进行操作,如果这有任何区别的话。

实时警报和记录器警报通常被视为相同,因此我可能会在大多数时间处理所有警报,而不是以不同方式处理记录器警报和实时警报。

记录器具有位于位置表中的相当具体的列。由于位置和记录器将是1对1的映射,我决定不使用单独的记录器表,到目前为止它似乎工作得很好并保持简单。示例列:LoggerRFID(int),LoggerUpperLimit(float),LoggerLowerLimit(float)等。您几乎可以争辩说记录器是一个传感器,但我走了那条路并且结果并不太好。

我几乎可以接受使警报通用,但正如其中一个答案所说,我正在努力确保这一点,所以在选择特定路径之前尽可能地继续研究。

3 个答案:

答案 0 :(得分:1)

您可以在选项一中向镜像表添加ObjectType列,并提供Sensor或Logger的值。您的数据库设计将如下所示:

Location [Table]
- Id
- Name
- HasLogger

ObjectType [Table]
- Id [PK]
- Name -- either Sensor or Logger
- Description

Object [Table]
- Id [PK]
- LocationId [FK]
- ObjectTypeId [FK]

Reading [Table]
- Id [PK]
- ObjectId [FK]
- Value

ObjectReading
- ObjectId [FK]
- ReadingId [FK]

Alert [Table]
- Id [PK]
- ReadingId [FK]

AlertCorrectiveAction [Table]
- AlertId [FK]
- CorrectiveActionId [FK]
- ByUserId [FK]

AlertAcknowledgement [Table]
- AlertId [FK]
- ByUserId [FK]

这种设计确实模糊了数据库的基本目的,很大程度上是因为我想不出一个更好的词来描述“传感器或记录器”而不是“对象” - 如果有一些特定术语可以集体描述某些东西附在一个位置,这肯定有助于理解数据库。

如果您对表中的非整数ID并不特别陌生,您还可以从ObjectType中删除Id列并使Name成为主键。我对使用ObjectType这样的表有不好的经验,其中主键不是整数,所以我几乎总是使用一个。

我同意KM上面的评估,即每个表的主键ID的名称应该比“Id”长。

答案 1 :(得分:1)

关于此的一些想法(想法和意见,而不是答案):

“supertable”(类型/子类型)模型引人注目,但实现和支持可能很棘手。一些技巧:

ALERT
  AlertId    PK 1/2
  AlertType  PK 2/2  Check constraint (1 or 2, or better L or S)

...即复合主键,其中“type”必须始终为L)og或S)ensor。

LOGALERT
  LogAlertId  PK 1/2  FK 1/2
  AlertType   PK 2/2  FK 2/2

(and again for SENSORALERT)

...也就是说,同一个复合主键,外键在两列上。以这种方式完成,给定类型表只能有一个子类型表,顶部表清楚地显示涉及哪个子类型。无法强制执行子类型表中存在的行,因此请仔细设置数据。使用视图可以处理(覆盖?)大部分查询复杂性。

缺点是,对于那些尚未熟悉它的人来说,这很复杂,令人困惑,需要额外的支持和努力。真正的问题是,它值得吗?

  • 您必须多久处理所有警报,而不仅仅是Log还是仅传感器?如果大多数时候你只需要处理其中一个,那可能就不值得了。
  • 您需要处理多少特定​​于日志或传感器的详细信息?除了与单个警报相关的实际事件之外,两种类型的相似之处是您将跟踪的无数属性(列中的详细信息)?如果用户,知识和纠正措施(足够)是相同的,那么你可以使它们成为ALERT的属性(列),但如果没有,那么你必须使它们成为相应子类型的属性,并且你失去了超类型的整合优势。
  • 在设计期间,您必须立即纠正它。研究,提出问题,凝视水晶球(即思考将来可能发生的事情,使每个人的当前的假设无效),因为如果你现在错了,你和你的继任者可能必须永远忍受它

答案 2 :(得分:1)

我认为您的other question已经使用完整的数据模型回答了这个问题;否则(如果有任何遗漏),请在此问题上发布编辑。

如果您对超类型 - 子类型关系结构感兴趣,一般来说,this question可能会让您感兴趣。

我建议你关闭这个问题。