Sql 关于传感器/读数/警报数据库设计的意见
最近我问了一些关于数据库设计的问题,可能太多了;-)然而,我相信,我正在慢慢地触及我的设计的核心,并慢慢地将其煮沸。关于如何将“警报”存储在数据库中,我仍在绞尽脑汁做几个决定 在这个系统中,警报是一个必须被确认、采取行动等的实体 最初,我将读数与如下警报相关(非常精简):- 最后一个表将读数与警报关联,因为正是读数指示传感器是否处于警报状态 这种设计的问题在于,它允许来自多个传感器的读数与单个警报相关联,而每个警报仅针对单个传感器,并且应该仅具有与之相关的传感器读数(我是否应该担心DB允许这种情况?) 我想,为了简化事情,为什么还要麻烦阅读表格呢?相反,我可以这样做:Sql 关于传感器/读数/警报数据库设计的意见,sql,database,database-design,relational-database,Sql,Database,Database Design,Relational Database,最近我问了一些关于数据库设计的问题,可能太多了;-)然而,我相信,我正在慢慢地触及我的设计的核心,并慢慢地将其煮沸。关于如何将“警报”存储在数据库中,我仍在绞尽脑汁做几个决定 在这个系统中,警报是一个必须被确认、采取行动等的实体 最初,我将读数与如下警报相关(非常精简):- 最后一个表将读数与警报关联,因为正是读数指示传感器是否处于警报状态 这种设计的问题在于,它允许来自多个传感器的读数与单个警报相关联,而每个警报仅针对单个传感器,并且应该仅具有与之相关的传感器读数(我是否应该担心DB允许这种情
[Location]
LocationId
[Sensor]
SensorId
LocationId
[SensorReading]
SensorReadingId
SensorId
Value
Status
Timestamp
[SensorAlert]
SensorAlertId
SensorId
Timestamp
[SensorAlertEnd]
SensorAlertId
Timestamp
基本上,我现在并没有将读数与警报联系起来——相反,我只知道警报在特定传感器的开始和结束时间之间处于活动状态,如果我想查找该警报的读数,我可以这样做
显然,缺点是我不再有任何约束阻止我删除警报期间发生的读数,但我不确定该约束是否必要
现在,从外部看,作为一名开发人员/DBA,这会让你感到恶心吗?或者这看起来合理吗
有没有其他我可能不知道的方法
谢谢
编辑:
这里还有一个想法——它以不同的方式工作。它将每个传感器状态的变化(从正常状态到警报状态)存储在一个表中,然后读数仅与特定状态关联。这似乎解决了所有的问题-你认为呢?(我唯一不确定的是将表命名为“SensorState”,我不禁想到还有更好的名称(可能是SensorReadingGroup?):-
必须有一个优雅的解决方案!您必须处理的主要“三角形”是传感器、[传感器]读数和警报。假设您必须跟踪正在发生的活动(而不是“一次加载所有内容”的设计),您的第三个解决方案与我们最近所做的类似。稍作调整,它看起来会像:
[Location]
LocationId
[Sensor]
SensorId
LocationId
CurrentSensorState -- Denormalized data!
[SensorReading]
SensorReadingId
SensorState
Value
Timestamp
[SensorStateLog]
SensorId
Timestamp
SensorState
Status -- Does what?
IsInAlert
(Primary key is {SensorId, Timestamp})
“SensorState”可以是SensorStateId,并带有一个相关联的查找表,列出(并约束)所有可能的状态
想法是,每个传感器包含一行,并显示其当前状态。传感器读数随传感器读数不断更新。如果给定传感器的当前状态发生变化(即新读数的状态与传感器的当前状态不同),则,您可以更改当前状态,并在SensorStateLog中添加一行,显示状态的更改。(可选地,您可以使用“状态结束”时间戳更新该传感器的“Previor”条目,但这是需要编写的繁琐代码。)
传感器表中的CurrentSensorState是非规范化数据,但如果正确维护(如果有数百万行),则查询当前状态的效率将大大提高,因此可能值得付出努力
所有这些的明显缺点是警报不再是一个实体,它们变得更难跟踪和识别。如果这些警报必须易于识别和使用,那么您的第三个方案将无法完成您需要它完成的任务。这是我对这个问题的两分钱 AlertType表格包含所有可能的警报类型。
AlertName
可能是高温、低压、低水位等
警报设置表格允许从传感器设置特定警报类型的警报阈值。
例如,TresholdLevel
=100和TresholdType
='HI'应触发读数超过100的警报
读取表在传感器读数流入服务器(应用程序)时保存传感器读数
警报表格保存所有警报。它保留指向触发警报的第一次读取和最后一次读取的链接(FirstReadingId
,LastReadingId
)。如果(SensorId
,AlertTypeId
)存在活动警报,则为“激活”
组合。IsActive
只能通过读取低于警报阈值的值才能设置为false。isackknowledged
表示操作员已确认警报
读取ID
SensorId
,AlertTypeId
)组合的警报设置检查读数。此时将创建对象集合{SensorId,AlertTypeId,ReadingId,IsAlert}
,并为每个对象设置IsAlert
标志{SensorId、AlertTypeId、ReadingId、IsAlert}
的活动警报
- 如果
为真,并且(IsAlert
,SensorId
)没有激活的警报组合后,将一个新行添加到警报表中,其中AlertTypeId
指向当前FirstReadingID
。将ReadingId
设置为TRUE,将IsActive
设置为FALSEisackknowledged
- 如果
为真且(IsAlert
,SensorId
)组合存在活动警报,则通过设置指向当前AlertTypeId
的ReadingId
来更新该行LastReadingID
- 如果
为假,并且(IsAlert
,SensorId
[Location] LocationId [Sensor] SensorId LocationId [SensorState] SensorStateId SensorId Timestamp Status IsInAlert [SensorReading] SensorReadingId SensorStateId Value Timestamp
[Location] LocationId [Sensor] SensorId LocationId CurrentSensorState -- Denormalized data! [SensorReading] SensorReadingId SensorState Value Timestamp [SensorStateLog] SensorId Timestamp SensorState Status -- Does what? IsInAlert (Primary key is {SensorId, Timestamp})
INSERT Sensor VALUES ( @LocationId, SensorNo = ( SELECT ISNULL(MAX(SensorNo), 0) + 1 FROM Sensor WHERE LocationId = @LocationId ) @SensorCode ) -- Assume @LoopDateTime contains the DateTime of the last iteration INSERT Alert SELECT LocationId, SensorNo, ReadingDtm, "L" -- AlertType "Low" FROM Sensor s, Reading r WHERE s.LocationId = r.LocationId AND s.SensorNo = r.SensorNo AND r.ReadingDtm > @LoopDtm AND r.Value < s.LowerLimit INSERT Alert SELECT LocationId, SensorNo, ReadingDtm, "H" -- AlertType "High" FROM Sensor s, Reading r WHERE s.LocationId = r.LocationId AND s.SensorNo = r.SensorNo AND r.ReadingDtm > @LoopDtm AND r.Value > s.UpperLimit