在 TableStorage 中查找第一个匹配条件的元素的最聪明和最有效的方法

Smartest and Most Performant Way to find the First Element Matching a Condition in a TableStorage

假设我有一个巨大的 table 存储客户的存储空间。假设 Partition Key 是他们的邮政编码,RowKey 是他们的注册时间戳。

现在,找到给定(邮政编码)区域的第一个客户(在给定日期后注册(早起的鸟儿:-))的最聪明、最有效的方法是什么?假设条目在写入 table 存储时未排序。

我最初的想法是有一个像这样的辅助方法(无论如何我都需要它用于其他目的):

public IEnumerable<Customer> GetCustomers(string zip, long stampStart, long stampEnd)
{
    if (_table == null) return new List<Customer>();

    return query = (from entry in _table.CreateQuery<Customer>()
        where entry.PartitionKey == zip
        && entry.RowKey.CompareTo(stampStart) <= 0 
        && entry.RowKey.CompareTo(stampEnd) >= 0
                 select entry);
}

然后用它来触发这样的请求:

public Customer GetEarlyBird(string zip, long stamp)
{
    if (_table == null) return null;

    return
        GetCustomers(zip, stamp, stamp + 31536000) //covers a one year period
            .OrderBy(x => x.SignupStamp)
            .FirstOrDefault();
}

最后调用

var zip = //some zip code;
var lookupStamp = //some long timestamp;
var earlyBird = GetEarlyBird(zip, lookupStamp);

但是,由于 OrderBy 调用,必须对整个查询结果进行评估,这需要很长时间。另一方面,在不对查询结果进行排序的情况下,FirstOrDefault 不一定 return 在 stamp 之后注册最近的客户,而是列表中的第一个(可以是该地区的任何客户,因为他们存储在 table 中时不一定被排序)。

我错过了什么? "outsource" 向数据库排序而不是在内存中排序的最聪明的方法是什么?或者我的方法是否还有其他一些我遗漏的主要缺陷?

如果将注册时间戳转换为 DateTime.Ticks,然后从 DateTime.Max.Ticks 中减去并将其用作行键,Azure Table 存储服务将自然地对最新条目进行排序在顶部,因为它将具有最小的行键。因此,如果您使用 Take(1) 使用特定分区键进行查询,您将检索该分区键的最新条目。这样就没有分区扫描,客户端和服务都没有过滤。

正如 Dogu Arslan 所说,您可以使用 DateTime.Ticks 成为您的行键并使用 take 方法获取第一个值。

更多详情,您可以参考以下代码:

    DateTime d1 = new DateTime(2016, 11, 1);
        DateTime d2 = new DateTime(2016, 12, 1);
        var query = (from ent in query2
                     where
                         ent.PartitionKey == "ZIP"
                       && ent.RowKey.CompareTo(string.Format("{0:D19}", d1.Ticks)) > 0
                      && ent.RowKey.CompareTo(string.Format("{0:D19}", d2.Ticks)) < 0
                     select ent).Take(1).FirstOrDefault() ;

我建议你也可以注意以下事项:

1.If 您想要获得在给定日期之后首先注册的人。 我建议您可以直接使用 DateTime.Now.Ticks,因为 azure table 会自动按分区键和行键升序对实体进行排序。 早期时间刻度将小于现在时间刻度。

2.You 必须用前导零填充反向刻度值,以确保字符串值按预期排序。 更多详情,您可以参考下图: