Azure Table:选择分区键以按时间和用户 ID 高效地对记录进行排序
Azure Table: Choose a partition key to efficiently sort records by time and user id
我目前正在跟踪 Azure Table 中的 API 调用元数据,其中 PartitionKey
是 UserId
并且 RowKey
是随机的 Guid
.这有助于我查询属于特定用户的记录。但是,我需要定期将数据迁移到分析服务,以获取有关 API 调用频率、平均响应时间等信息。我需要想出更好的 PartitionKey
策略来执行此操作.
这些是我正在为 PartitionKey
考虑的选项:
1) 将当前 UTC 时间四舍五入到最接近的分钟并将其转换为滴答。 这允许我使用时间间隔定期下载数据,但我无法有效地查看上传与特定用户关联的数据。
2) 使用由 {ticks}_{userId} 组成的合成键。 是否可以执行像 Where(m => m.PartitionKey.Contains(ticks))
或 [=18 这样的过滤查询=]?如果是这样,这是一种可扩展的方法吗?
3) 保存两条记录(一条带刻度,另一条以 userId 为分区键)。 如果我采用这种方法,我如何确保两条记录都被保存一直假设没有办法执行原子事务?
对我来说,现在最重要的是按时间对记录进行排序。因此,我主要考虑改变我的逻辑以适应#1。但是,我想知道是否可以按时间和用户 ID 高效地查询记录。
1) Round down current UTC time to the nearest minute and convert it to
ticks. This allows me to download data periodically using time
intervals, but I can't efficiently look up data associated to a
specific user.
这种方法肯定适用于通过 date/time 获取 API 调用,但是如果您需要通过用户获取数据,那么这种方法将失败,因为完整的 table 扫描需要待执行。
2) Use a synthetic key made up of {ticks}_{userId}. Is it possible to
execute a filtered query like Where(m =>
m.PartitionKey.Contains(ticks)) or Where(m =>
m.PartitionKey.Contains(userId))? If so, is this a scalable approach?
不幸的是,这种方法不起作用,因为 Azure 表不支持 Contains
查询。您可以在此处找到受支持的 LINQ OData 查询运算符列表:https://docs.microsoft.com/en-us/rest/api/storageservices/query-operators-supported-for-the-table-service.
3) Save two records (one with ticks and another with userId being the
partition key). If I go with this approach, how do I ensure that both
records are saved all the time assuming there is no way to enforce an
atomic transaction?
到目前为止,这是最好的方法。在这种情况下,您将存储两条记录 - 一条带有代表 date/time 标记的分区键,另一条带有用户 ID 作为分区键。事实上,这是我在我的项目中广泛使用的东西。
关于您对原子事务的评论,您是完全正确的。因为您使用的是 2 个单独的分区键,所以您不能使用实体批处理事务。
我所做的是在我的应用程序中实现最终一致性模式。当我收到请求时,我只是将请求作为消息保存在存储队列中。如果我能够编写消息,那么我的实体最终将在存储中可用。接下来我编写了一个函数,只要消息保存在队列中就会触发该函数。此函数将读取消息,然后使用 InsertOrReplace
语义写入 2 个单独的实体,以确保数据最终保存在 table.
中
我目前正在跟踪 Azure Table 中的 API 调用元数据,其中 PartitionKey
是 UserId
并且 RowKey
是随机的 Guid
.这有助于我查询属于特定用户的记录。但是,我需要定期将数据迁移到分析服务,以获取有关 API 调用频率、平均响应时间等信息。我需要想出更好的 PartitionKey
策略来执行此操作.
这些是我正在为 PartitionKey
考虑的选项:
1) 将当前 UTC 时间四舍五入到最接近的分钟并将其转换为滴答。 这允许我使用时间间隔定期下载数据,但我无法有效地查看上传与特定用户关联的数据。
2) 使用由 {ticks}_{userId} 组成的合成键。 是否可以执行像 Where(m => m.PartitionKey.Contains(ticks))
或 [=18 这样的过滤查询=]?如果是这样,这是一种可扩展的方法吗?
3) 保存两条记录(一条带刻度,另一条以 userId 为分区键)。 如果我采用这种方法,我如何确保两条记录都被保存一直假设没有办法执行原子事务?
对我来说,现在最重要的是按时间对记录进行排序。因此,我主要考虑改变我的逻辑以适应#1。但是,我想知道是否可以按时间和用户 ID 高效地查询记录。
1) Round down current UTC time to the nearest minute and convert it to ticks. This allows me to download data periodically using time intervals, but I can't efficiently look up data associated to a specific user.
这种方法肯定适用于通过 date/time 获取 API 调用,但是如果您需要通过用户获取数据,那么这种方法将失败,因为完整的 table 扫描需要待执行。
2) Use a synthetic key made up of {ticks}_{userId}. Is it possible to execute a filtered query like Where(m => m.PartitionKey.Contains(ticks)) or Where(m => m.PartitionKey.Contains(userId))? If so, is this a scalable approach?
不幸的是,这种方法不起作用,因为 Azure 表不支持 Contains
查询。您可以在此处找到受支持的 LINQ OData 查询运算符列表:https://docs.microsoft.com/en-us/rest/api/storageservices/query-operators-supported-for-the-table-service.
3) Save two records (one with ticks and another with userId being the partition key). If I go with this approach, how do I ensure that both records are saved all the time assuming there is no way to enforce an atomic transaction?
到目前为止,这是最好的方法。在这种情况下,您将存储两条记录 - 一条带有代表 date/time 标记的分区键,另一条带有用户 ID 作为分区键。事实上,这是我在我的项目中广泛使用的东西。
关于您对原子事务的评论,您是完全正确的。因为您使用的是 2 个单独的分区键,所以您不能使用实体批处理事务。
我所做的是在我的应用程序中实现最终一致性模式。当我收到请求时,我只是将请求作为消息保存在存储队列中。如果我能够编写消息,那么我的实体最终将在存储中可用。接下来我编写了一个函数,只要消息保存在队列中就会触发该函数。此函数将读取消息,然后使用 InsertOrReplace
语义写入 2 个单独的实体,以确保数据最终保存在 table.