如何在 Azure Table 存储中使用 RowKey 或时间戳检索最新记录

How to retrieve latest record using RowKey or Timestamp in Azure Table storage

棘手的部分是 RowKeystring,它的值类似于 Mon Nov 14 12:26:42 2016

我尝试使用 Timestamp 查询

var lowerlimit = DateTime.UtcNow; // its should be nearer to table timestamp data.
            TableQuery<TemperatureEntity> query2 = new TableQuery<TemperatureEntity>().Where(TableQuery.GenerateFilterConditionForDate("Timestamp", QueryComparisons.GreaterThanOrEqual,lowerlimit));
            var test = table.ExecuteQuery(query2);

MyEntity.cs

  public class MyEntity : TableEntity
    {
        public MyEntity(string partitionKey, string rowKey)
        {
            this.PartitionKey = partitionKey;
            this.RowKey = rowKey;
        }

        public MyEntity() { }

        public Int64 DevideId { get; set; }

        public string RowKey { get; set; }
    }

//下面的查询给出了完整的数据 Program.cs

// Retrieve the storage account from the connection string.
            CloudStorageAccount storageAccount = CloudStorageAccount.Parse(
                CloudConfigurationManager.GetSetting("StorageConnectionString"));

            // Create the table client.
            CloudTableClient tableClient = storageAccount.CreateCloudTableClient();

            // Create the CloudTable object that represents the "TemperatureData" table.
            CloudTable table = tableClient.GetTableReference("TemperatureData");

            // retrive data
            TableQuery<TemperatureEntity> query = new TableQuery<TemperatureEntity>();
            var data = table.ExecuteQuery(query);

Azure Table 服务不支持 Order By 功能,因此当前设置的唯一选项是下载所有实体并在客户端按时间顺序对它们进行反向排序。当 table 中的实体数量变大时,这显然不是最佳解决方案。

其他选项(这将需要您重新设计应用程序)是将 date/time 值转换为反向刻度:

var rowKey = (DateTime.MaxValue.Ticks - DateTimeValueForRowKey.Ticks).ToString("d19")

这将确保将最新的条目添加到 table 的顶部而不是 table 的底部。要获取最新条目,您只需从 table.

中获取第一个实体

尼奥,

如果您需要在分区中拥有最新的条目,使用字符串日期时间作为行键不是一个好方法,因为 Table 存储基于行键以升序存储实体。

如果当前您可以更改行键的值,请使用 DateTime.UtcNow.Ticks:

var invertedTimeKey = DateTime.MaxValue.Ticks - DateTime.UtcNow.Ticks

使用这种方法,在查询您的 table 时,您将能够获取与最新对应的 1 个条目。

如果您无法更改行键的值,则必须检索分区中的所有条目,这意味着将所有条目加载到内存中,然后使用时间戳对它们进行排序以检索最后一个条目.如果你有很多条目,这绝对不是一个好方法。

var lastResult = results.OrderByDescending(r => r.Timestamp).FirstOrDefault();

可能某些情况下工作良好的另一种方法是“smartly-brute-force”table生成一个 range-query 或一组 range-queries,用于您希望工作的值并触发它们 all-at-once.

在这种情况下,由于 row-key 的格式为 Mon Nov 14 12:26:42 2016(假设 OP @neo 无法更改它),他们最想要 recent-results ,那么你可以通过前缀查询获得良好的性能(仍然是字典序 range-query) which Azure says is the fastest type of non-exact query:

Second best is a Range Query that uses the PartitionKey and filters on a range of RowKey values to return more than one entity. The PartitionKey value identifies a specific partition, and the RowKey values identify a subset of the entities in that partition. For example: $filter=PartitionKey eq 'Sales' and RowKey ge 'S' and RowKey lt 'T'.

使这项工作的一个巧妙技巧是 advantage-of 是 Mon Nov 14 只会是这些日期的事实:

1977-11-14
1983-11-14
1988-11-14
1994-11-14
2005-11-14
2011-11-14
2016-11-14
2022-11-14
2033-11-14
2039-11-14
2044-11-14
etc

因此,简单地对 Mon Nov 14 进行前缀搜索将安全地 return 隐式所需年份(2016 年)的记录,并且可能可以安全地排除其他 1 或 2 年 in-memory 没有显着的性能影响(例如 2011 年和 2022 年)。

请注意,如果您为 PartitionKey 提供了准确的值,Azure 只会使用真实的 range-query,在本例中始终为 "raspberrypi"。 OP 的原始查询没有。

String partitionKeyFilter = TableQuery.GenerateFilterCondition(
    propertyName: "PartitionKey",
    operation   : QueryComparisons.Equal,
    givenValue  : "raspberrypi"
);

DateTime today = DateTime.UtcNow;
String todayPrefix = today.ToString( "ddd MMM dd", CultureInfo.InvariantCulture );

String rowKeyFilter = TableQuery.GenerateFilterCondition(
    propertyName: "RowKey",
    operation   : QueryComparisons.GreaterThan,
    givenValue  : todayPrefix 
);

TableQuery<TemperatureEntity> query = new TableQuery<TemperatureEntity>()
{
    FilterString = TableQuery.CombineFilters( partitionKeyFilter, TableOperators.And, rowKeyFilter );
}

List<TemperatureEntity> queryResults = table
    .ExecuteQuery( query )
    .Where( e => e.RowKey.EndsWith( today.ToString(" yyyy") ) ) // Filter current-year in the client.
    .ToList();