c# - Azure 数据表 - RowKey 作为 DateTime.Ticks 的正确用法?

标签 c# azure azure-storage

我正在开发一个涉及 Azure IOT 中心和 Azure Functions 的 Azure 项目。

我有大约 50 个传感器,每 10 秒向 IOT 中心发送一条新消息。

每次 Azure IOT 中心收到新消息时,我都想执行一个函数来读取发送的消息并将其保存到 Azure 表存储中。

目前,我有点不知道应该使用哪种 Azure 表存储设计。到目前为止,这是我建议的表存储设计:

[PartitionKey][RowKey][TimeStamp][SensorSerial][Reading][Type]

这是数据在 Azure 存储资源管理器中的样子的模型:

 [GroupA][?][2017-05-03T12:20:22.713Z][xxx][60][Temperature]
 [GroupA][?][2017-05-03T12:25:22.713Z][xxx][61][Temperature]
 [GroupA][?][2017-05-03T12:30:22.713Z][xxx][59][Temperature]
 [GroupB][?][2017-05-03T12:35:22.713Z][yyy][90][Humidity]
 [GroupB][?][2017-05-03T12:40:22.713Z][yyy][92][Humidity]

我已将 RowKey 保留为“?”暂时因为它与手头的问题有关。

问题是我希望能够根据 SensorSerial 和指定的时间范围查询表存储数据 - 例如获取过去 15 秒的所有 xxx 读数

以下查询始终不返回任何数据:

TableQuery<Readings> rangeQuery = new TableQuery<Readings>().Where(
TableQuery.CombineFilters(
    TableQuery.GenerateFilterCondition("SensorSerial", QueryComparisons.Equal, "xxx"),
    TableOperators.And,
    TableQuery.GenerateFilterConditionForDate("TimeStamp", 
    QueryComparisons.GreaterThanOrEqual, DateTime.Now.AddSeconds(-15))));

从我到目前为止所读到的内容来看,我不确定为什么会这样 - 无法根据时间戳字段过滤数据。因此,您必须使用 RowKey 作为某种伪 TimeStamp 日期时间刻度字段。

所以为了解决这个问题,我计划使用它作为我的 RowKey 值

var RowKey = string.Format("{0:D19}", DateTime.MaxValue.Ticks - DateTime.UtcNow.Ticks);

它将满足此查询并返回必要的值:

TableQuery<Readings> query = new TableQuery<SensorEntity>().Where(
TableQuery.CombineFilters(
(TableQuery.GenerateFilterCondition("SensorSerial", QueryComparisons.Equal, "xxxx")), 
TableOperators.And,
(TableQuery.GenerateFilterCondition("RowKey", QueryComparisons.LessThanOrEqual, 
"2519084875883616261"))));

但是,我在这里可能是错的,这种方法可能会导致一些问题,因为以下原因>:

如果两个或多个传感器同时/间隔传输数据怎么办?在一个传感器插入新行时,RowKey 必须是唯一的进入Azure存储,其他将无法逗留。

我可以运行代码,希望传输/数据处理/插入会导致足够的延迟,永远不会引起任何问题,但依赖它会很糟糕。

还有更好的办法吗?一种更安全的方法,允许我根据指定时间和唯一设备标识符查询 Azure 数据表存储?

最佳答案

让我们首先谈谈您当前的方法。

目前您所采取的方法还不错。该方法的优点是您使用反向刻度 (DateTime.MaxValue.Ticks - DateTime.UtcNow.Ticks) 这将确保将最新数据添加到表格顶部位于表格底部,因此只要您查询最近 x 分钟/小时的数据,检索就会非常快。

我发现这种方法存在一些问题:

  • 随着数据的增长,当您希望查询真正旧的数据时,您将遇到发生分区扫描的情况。这比全表扫描要好一些,但如果可能的话应该避免。
  • 您将所有内容都放在一张表中,因此您最终会到达 scalability limits由表服务强加,因为所有读/写都只发生在一张表上。这将对性能产生不利影响。

可能的解决方案

一种可能的解决方案(目前考虑您的查询针对传感器)是为每个传感器创建一个单独的表,然后将该传感器的数据存储在指定的表中。我认为这种方法的优点是:

  • 由于每个传感器都有自己的表,因此您基本上释放了一把 key 。在这种情况下,您可以使用 PartitionKey 作为反向刻度,并将 RowKey 用作您喜欢的任何其他值。我建议为 PartitionKey 存储更高粒度的刻度(例如一个小时),并保持 RowKey 不变。这将确保您最终不会创建大量分区。
  • 由于每个传感器数据都存储在单独的表中,因此您可以将它们放入不同的存储帐户中。因此,SensorA 表可能位于存储帐户 A 中,Sensor B 表可能位于存储帐户 B 中。这样,您实质上就可以对不同表/存储帐户之间的流量进行负载平衡,并实现更好的可扩展性和吞吐量。

显然,这种方法的缺点是它会给您带来更多的管理麻烦。您需要拥有某种主数据库,在其中保存传感器及其关联存储帐户之间的关联。这种方法的另一个缺点是您将无法仅查询时间戳(我的第二个问题)。为此,您可以使用您所采取的方法在另一个存储帐户中仅保留一张表。

关于您的评论如果两个或更多传感器同时/间隔传输数据怎么办? RowKey 必须是唯一的,当一个传感器将新行插入 Azure 存储时,另一个传感器将无法再插入新行。,本质上 RowKey 在分区或其他分区中必须是唯一的单词PartitionKey + RowKey组合在表中必须是唯一的。所以我认为这不会成为问题。

关于c# - Azure 数据表 - RowKey 作为 DateTime.Ticks 的正确用法?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/43762117/

相关文章:

c# - 使用哪个 linq 在当前集合中的集合中进行集合搜索

c# - 如果它是数据表的第一行,如何增加变量

ios - 集成 Office-365-SDK-for-iOS

azure - 在资源管理器(新门户)中为 Azure Blob 存储设置自定义域

azure - Windows Azure 数据中心位置在哪里?

c# - 带按钮的 TreeView 多级自定义模板

c# - ASP.NET WebAPI 创建一级 JSON

c# - Azure EventHubs 抛出异常 : At least one receiver for the endpoint is created with epoch of '0' ,,因此不允许使用非纪元接收器

php - 将默认值为空的非空列保留为空白时出现 MySQL 错误 1366

azure - 如何将多域用户电子邮件添加到 Azure AD