物联网应用的数据库设计

Database design for IoT application

我们的应用程序显示客户远程设备的近实时物联网数据(最多 5 分钟间隔)。

最初的试点项目在 SQL Server 2008 数据库上的简单“测量”table 中始终存储每个设备读数。 table 看起来像这样:

Measurements: (DeviceId, Property, Value, DateTime).

在一两年内,每个设备 table 中可能会有 100,000 条记录,查询通常分为两类:

我们现在正在扩展到 5000 台设备。 Measurements table 现在很小,但很快就会达到 50 亿条左右的记录,仅针对这 5000 台设备。

该应用程序是读取密集型应用程序,经常 运行 查询特别是查看“设备最新值”。

[编辑 #1:减少基于意见的]

我们可以使用哪些数据库设计技术来优化“最新”物联网值的快速读取,给定具有多年“历史”物联网价值的大 table?

我们团队的一个建议是将 MeasurementLatestMeasurementHistory 存储为两个单独的 table。

[编辑#2:回应反馈]

在我们的测试数据库中,有 5000 万条记录,并应用了以下索引:

CREATE NONCLUSTERED INDEX [IX_Measurement_DeviceId_DateTime] ON Measurement (DeviceId ASC, DateTime DESC)

典型的“获取设备最新值”查询(如下所示)仍然需要超过 4,000 毫秒才能执行,这对于我们的需求来说太慢了:

SELECT DeviceId, Property, Value, DateTime
FROM Measurements m
WHERE m.DateTime = (
  SELECT MAX(DateTime) 
  FROM Measurements m2
  WHERE m2.DeviceId = m.DeviceId)

这是一个非常广泛的问题 - 因此,您不太可能得到明确的答案。

但是,我也遇到过类似的情况,我会运行通过我的思考和最终的方法。总而言之——我做了选项 B,但在某种程度上反映了选项 A:我使用过滤索引 'mimic' 单独的较小 table.

我最初的想法是有两个 table - 一个用于大多数报告的 'latest data only',然后一个具有所有历史值的 table。另一种方法是有两个 tables - 一个包含所有记录,一个包含最新记录。

插入新行时,通常需要更新至少两行,如果不是更多(取决于它的存储方式)。

相反,我选择了一条稍微不同的路线

  • 将所有数据合为一体table
  • 在那个 table 上,添加一个新列 'Latest_Flag'(位,NOT NULL,DEFAULT 1)。如果它是 1 那么它就是最新的值;否则它是历史的
  • 在 table 上有一个 filtered index,它具有所有列(具有适当的列顺序)和过滤器 Latest_Flag = 1
    • 此筛选索引类似于 table 的第二个副本,仅包含最新行
  • 插入过程因此在事务中有两个步骤
    • 'Unflag' 该设备的最后一个 Latest_Flag,等等
    • 插入新行

它仍然使写入速度稍慢(因为它需要进行多个行更新以及索引更新)但从根本上说,它会为以后的读取进行预计算。

但是,当从 table 读取时,您需要指定 WHERE Latest_Flag = 1。或者,您可能希望将其放入视图或类似视图中。

对于过滤后的索引,可能是这样的

CREATE INDEX ix_measurements_deviceproperty_latest 
    ON Measurements (DeviceId, Property)
    INCLUDE (Value, DateTime, Latest_Flag)
    WHERE (Latest_Flag = 1)

注意 - 另一个版本可以在触发器中完成,例如,当插入新行时,它会使之前的任何行无效(设置 Latest_Flag = 0)。这意味着您不需要进行两步插入;但是你确实依赖于 business/processing 触发器中的逻辑。