Azure表存储查询partitionkey

时间:2016-04-14 07:38:16

标签: c# azure azure-sql-database azure-storage azure-table-storage

我正在使用Azure表存储来通过时间戳过滤器检索数据。我发现执行速度非常慢,因为时间戳不是分区键或行键。我研究了stackoverflow,发现时间戳应该转换为ticks并存储到Partition键中。我做了同样的事情,在插入数据时我采用了下面的字符串,并将tick字符串插入分区键。

string currentDateTimeTick = ConvertDateTimeToTicks(DateTime.Now.ToUniversalTime()).ToString();

public static long ConvertDateTimeToTicks(DateTime dtInput)
{
    long ticks = 0;
    ticks = dtInput.Ticks;
    return ticks;
}

直到这里这很好。但是当我尝试检索最近5天的数据时,我无法查询对分区键的勾选。我想获取最近5天的数据。我在下面的代码中犯了什么错误?

int days = 5;
TableQuery<MyEntity> query = new TableQuery<MyEntity>()
.Where(TableQuery.GenerateFilterConditionForDate("PartitionKey", QueryComparisons.GreaterThanOrEqual, "0"+DateTimeOffset.Now.AddDays(days).Date.Ticks));

3 个答案:

答案 0 :(得分:9)

您确定要使用刻度线作为分区键吗?这意味着每个可测量的100 ns瞬间成为它自己的分区。使用基于时间的数据,您可以使用分区键指定每小时,分钟或甚至秒的间隔,然后指定具有实际时间戳的行键。

除了问题之外,让我告诉你如何进行查询。首先让我评论一下如何生成分区键。我建议你这样做:

var partitionKey = DateTime.UtcNow.Ticks.ToString("D18");

请勿使用DateTime.Now.ToUniversalTime()获取当前的UTC时间。它将在内部使用DateTime.UtcNow,然后将其转换为本地时区,ToUniversalTime()将转换回UTC,这只是浪费(并且比您想象的更耗时)。

您的ConvertDateTimeToTicks()方法除了获取Ticks属性之外没有任何其他目的,因此只是在不添加任何值的情况下使代码更加复杂。

以下是执行查询的方法:

var days = 5;
var partitionKey = DateTime.UtcNow.AddDays(-days).Ticks.ToString("D18")
var query = new TableQuery<MyEntity>().Where(
  TableQuery.GenerateFilterCondition(
    "PartitionKey",
    QueryComparisons.GreaterThanOrEqual,
    partitionKey
  )
);

分区键的格式为18个字符的字符串,允许您使用简单的比较。

我建议您移动代码以生成分区键(和行键)到函数中,以确保在整个代码中以相同的方式生成键。

使用18个字符的原因是因为今天Ticks的{​​{1}}值以及将来的数千年使用18个十进制数字。如果您决定将分区键基于小时,分钟或秒而不是100 ns的刻度,那么您可以相应地缩短分区键的长度。

答案 1 :(得分:8)

正如Martin所说,使用时间戳作为分区键几乎肯定不是你想要做的。

分区是Azure表存储中的比例单位,或多或少表示数据的物理分段。它们是一种可扩展性优化,允许您“存储硬件”以解决存储越来越多数据的问题,同时保持可接受的响应时间(传统上在数据存储中很难)。您可以通过为每行分配分区键来定义数据中的分区。几乎不可取的是每一行都存在于自己的分区中。

在ATS中,行键成为给定分区中的唯一键。因此,分区键+行键的组合是整个ATS表中的真正唯一键。

有很多建议可以选择有效的分区键和行键...其中没有一个是通用的。这取决于数据的性质,预期的查询模式等。

选择一个分区键,将您的数据聚合成一组分布均匀的“桶”。在所有条件相同的情况下,如果你预计你的表中有100万行,那么拥有10个每行100,000行的桶通常很有用......或者可能有100个桶,每行10,000行。在查询时,您需要选择要查询的分区,因此桶的数量可能对您很重要。 “桶”通常对应于您域中的自然分段概念...代表每个美国州的桶,或代表公司中每个部门的桶等。请注意,没有必要(或通常可能)完美分布式桶......尽可能接近,尽可能合理。

如果您打算通过存储桶来改变查询模式,那么您可能会故意分配不均匀的一个示例...存储桶A将收到大量便宜,快速的查询,存储桶B更少,查询更加昂贵等等。或者也许存储桶B数据频繁更改时,数据将保持静态。这也可以通过多个表来实现......所以没有“一刀切”的答案。

鉴于我们对您的问题知识有限,我喜欢Martin建议使用时间跨度作为您的分区键。小跨度将导致许多分区,并且(除其他外)使得利用多个时间跨度的查询相对昂贵。较大的跨度将导致跨越跨越的聚合成本更少,但会导致更大的分区,从而导致分区内更昂贵的查询(这也将使识别合适的行键更具挑战性。)

最终,您可能需要尝试一些选项,以便为您的数据和预期查询找到最合适的选项。

另一条建议......不要害怕考虑在多个数据存储中复制数据以适应各种各样的查询类型。并非每个查询都能有效地针对单个架构或存储配置。在商店之间同步数据所需的工作量可能少于您需要的弯曲查询技术X.

more on Partition and Row key choices

also here

祝你好运!

答案 2 :(得分:0)

上面的答案中没有提到的一件事是,Azure将检测您是否正在使用分区键的顺序,始终增加或始终减少的值,并创建“范围分区”。范围分区具有顺序唯一PartitionKey值的实体,以提高范围查询的性能。如上所述,如果没有范围分区,范围查询将需要跨越分区边界或服务器边界,这会降低查询性能。范围分区发生在引擎盖下,由Azure决定,而不是你。

现在,如果你想进行批量插入,让我们说每分钟一次,你仍然需要将你的时间戳分区键变平,比如,向上舍入到最接近的分钟。您只能使用相同的分区键进行批量插入。