0

我的任务是在数据库中存储大量 gps 数据和一些额外信息,并访问它以进行报告和其他一些不常见的任务。

当我从 gps 设备收到消息时,它可以有可变数量的字段。例如

消息 1:DeviceId Lat Lon Speed Course DIO1 ADC1
消息 2:DeviceId Lat Course DIO2 IsAlarmOn
消息 3:DeviceId Lat Lon Height Course DIO2 IsAlarmOn 等 最多 20-30 个字段

没有办法统一字段的数量——不同的设备供应商、不同的协议等。另一个令人头疼的问题是数据库的大小和支持尽可能多的数据库供应商的必要性(使用 NHibernate)。

所以我想到了以这种方式存储消息:
Table1 - Tracks
PK - TrackId
TrackStartTime
TrackEndTime
FirstMessageIndex(stores MessageId)
LastMessageIndex(stores MessageId)
DeviceId(not an FK)

表2 - Messages
PK - MessageId
TimeStamp
FirstDataIndex(stores DataId)
LastDataIndex(stores DataId)

表 3 - MessageData
PK - DataId
double Data
short DataType

所有索引都用 hilo 赋值。调整了我的查询,以便 Nhibernate 可以快速处理 3000+k 条消息(也使用了 baching)。我对性能 atm 感到满意。但我不知道它在 50+gb 或 100+gb 大小下如何工作。

将非常感谢有关我的问题和整体存储设计的任何提示和提示=)
谢谢,Alexey
PS。对不起我的英语=)

4

3 回答 3

3

简而言之,您的应用程序,特别是从 GPS 设备接收到的消息的异构结构,将您的设计推向EAV 数据存储结构(其中 Entity 是 Message , Attribute 是“MessageData.DataType”,而 Value 是系统的双倍。)

您在问题中概述的三个表设计,但是似乎与传统的 EAV 实现有所不同,从某种意义上说,MessageData 的存储方式存在隐式顺序,给定消息的所有数据点都按顺序编号( DataId),并且从消息到其数据点的链接将由 DataId 在一个范围内驱动。
这是个坏主意!许多问题,一个值得注意的问题是,这为插入消息引入了不必要的瓶颈,直到前一条消息的所有数据点都无法开始插入第二条消息。另一个问题是它使消息和数据点之间的关系难以索引(底层 DBMS 不会有效)。
==> 建议:做MessageId 是 MessageData表中的外键。(并且可能完全删除 MessageData 表中的 DataId PK,只是为了节省空间,代价是必须使用复合键来引用该表中的特定记录,例如出于维护目的)

另一个建议是将最常见的属性(数据点)存储在 Message table 的级别。例如,Lat 和 Long,但也可能是 Course 或 Some alarms 等。将这些信息正确用于消息的原因是为了优化对数据的查询(限制 MessageData 表所需的自连接数。

由于 Messages 和 MessageData 表都可能不包含消息的一部分,因此您可能还想重命名后一个 MessageDetail 表或类似的名称。

最后,允许双精度类型以外的数据值可能是个好主意。我预计一些警报只是布尔值等。除了允许您接受不同类型的数据点(比如简短的错误消息字符串......)之外,这还可能让您有机会将数据点拆分到多个“详细”表中:一个用于双打,一种用于布尔值,一种用于字符串等。这种方式使架构复杂化,因为您需要将其中一些细节构建到生成查询的方式中,但它可以为性能/扩展提供一些潜力收益。

于 2009-10-23T16:19:13.167 回答
0

我将尝试在回答中更详细地描述它的工作原理,因为注释具有固定长度=)这是接收顺序:
1. 服务从 MSMQ 接收消息(消息数量可以不同-atm 它使用 500 条消息批量数据包)。
2. 然后细化不同的设备 ID。
3. 对于每个设备 ID,它使用 MS EntLib 隔离存储缓存,其结构为:
DeviceId --> List 其中 DeviceId 是查找键。
4. 如果我们在缓存中有超过 1k 条消息 - 将它们按一个顺序写入 db,然后将“索引”写入查找表:
索引:id
serial_id
index_start_datetime
index_end_datetime
index_first_dataid
index_last_dataid
5. 清除此 DeviceId 的缓存

我还成对存储数据:id data1 data2 type
例如 lat lon、speed course、adc1 adc2、dio1、dio2 如果没有耦合值:值 0

我选择 double 因为我可以存储设备发送的每种类型的数据。不发送字符串,但大多数 em 都是 csv 样式,如 1,0,23,50.0000N30.00000,1,2,12,0,1,2 等。甚至警报等也具有相同类型的数据。当我需要获取一些数据时,我只需找到给定日期时间窗口和 DeviceId 的索引,并获取知道它何时开始和结束的实际数据。并且没有复杂的查询。只有2个简单的。其他代码正在使用一些协议“映射”来解释这一点。感谢 EAV 提示。我认为它很适合。第一个表 Track 用于聚合消息并在我之前描述的几个字符串的检索算法中快速获取它们。

于 2009-10-23T20:39:20.307 回答
0

我正在写类似的应用程序。我建议识别来自供应商的所有可能值,并创建包含所有必要字段的适当模式。多亏了这一点,您可以编写高性能/最简单的报告查询。

此外,您可以创建包含指定(长度)数据的字段,这意味着您可以节省空间并提高性能。

我有一个具有已知值的供应商,所以我为此创建了一个表。该表可以通过本机 MS SQL Server 机制轻松分区。

因此,我最简单的情况允许我编写一个存储过程来保存数据。没有NHibernate,只有纯ICommand。

应用程序的其余部分使用 NHibernate。

于 2009-12-27T22:51:23.450 回答