改善Azure表存储查询性能的建议

时间:2018-06-27 02:13:54

标签: azure-storage azure-table-storage azure-tablequery

Azure表存储中有一个表,由于它是新实现的,因此目前有50,000个项目。

PartitionKey :字符串形式的DateTime值
RowKey:以字符串形式的数字值

我们使用TableQuery生成过滤条件。 PartitionKey筛选器类似于:PartitionKey ge '201801240000000000' && "PartitionKey lt '201806220000000000'"

不幸的是,我们不能使用RowKey过滤器,因为我们需要两个日期之间的数据。

要获取大约一个月的数据,大约需要5秒钟。而要获取大约3个月的时间,则需要花费更多的时间。

尽管我们已经制定了缓存策略,但是第一次获取数据需要很长时间。就像数据过滤器在日期上更改一样,需要很长时间。

任何改善性能的建议都会受到赞赏。

2 个答案:

答案 0 :(得分:1)

据我从您的帖子中可以看到,最大的问题是您的查询跨越一个查询中的多个分区。这对于性能而言不是最佳的。根据以下列表,您位于 分区扫描 表扫描 之间,因为您指定分区键,但是您正在使用多个。

  
      
  • 点查询 是使用效率最高的查询,建议用于大量查询或要求最低延迟的查询。通过指定PartitionKey和RowKey值,这样的查询可以使用索引非常有效地定位单个实体。例如:$ filter =(PartitionKey eq'Sales')和(RowKey eq'2')
  •   
  • 第二好的是 Range Query (范围查询),该查询使用PartitionKey并对一系列RowKey值进行过滤以返回多个实体。 PartitionKey值标识特定的分区,而RowKey值标识该分区中实体的子集。例如:$ filter = PartitionKey eq'Sales'和RowKey ge'S'和RowKey lt'T'
  •   
  • 第三好是 分区扫描 ,该分区使用PartitionKey并对另一个非键属性进行筛选,并且可能返回多个实体。 PartitionKey值标识一个特定的分区,而属性值则为该分区中实体的子集选择。例如:$ filter = PartitionKey eq'Sales'和LastName eq'Smith'
  •   
  • 表扫描 不包含PartitionKey,并且效率很低,因为它会依次搜索组成表的所有分区以查找任何匹配的实体。无论过滤器是否使用RowKey,它都会执行表扫描。例如:$ filter = LastName eq'Jones'
  •   
  • 返回多个实体的查询将返回它们,并按PartitionKey和RowKey的顺序排序。为了避免在客户端中重新使用实体,请选择定义最常见排序顺序的RowKey。
  •   

来源:Azure Storage Table Design Guide: Designing Scalable and Performant Tables

这是另一篇非常有用的文章:What PartitionKey and RowKey are for in Windows Azure Table Storage,尤其是当您看这张图片时:

  

根据分区的大小和负载,分区在计算机之间呈扇形散开。每当分区的负载过大或大小增加时,Windows Azure存储管理都可以启动并将分区移至另一台计算机:   Partitioning

修改:
如果您想以多种方式查询数据,请考虑以多种方式存储它们。特别是由于存储价格便宜,因此多次存储数据并不是那么糟糕。通过这种方式,您可以优化阅读。这就是所谓的Materialized View pattern,它可以“帮助支持有效的查询和数据提取,并提高应用程序性能”。

但是,您应该记住,这对于静态数据很简单。如果您的数据变化很大,那么在多次存储时保持同步可能会很麻烦。

答案 1 :(得分:0)

rickvdbosch的答案就在现场。

这里有一些其他想法,假设这是一个应用程序。一种方法是并行读取较小的PartitionKey范围。例如,假设要处理的范围是 2018年6月,我们将:

  • 线程1 => PartitionKey ge'20180601'&& PartitionKey lt'20180605'
  • Thread-2 => PartitionKey ge'20180605'&& PartitionKey lt'20180610'
  • 线程3 => PartitionKey ge'20180610'&& PartitionKey lt'20180615'
  • 线程4 => PartitionKey ge'20180615'&& PartitionKey lt'20180620'
  • 线程5 => PartitionKey ge'20180620'&& PartitionKey lt'20180725'
  • 线程6 => PartitionKey ge'20180625'&& PartitionKey lt'20180701'

此外,无需使用TableQuery构造,甚至可以更主动地并行读取较小的分区(例如每天)。

请注意,上述两种方法都无法处理高度不平衡的分区策略。例如,假设6月/ 2018年的数据的95%存储在范围'20180605'至'20180610'或一天之内,那么与串行读入相比,总体执行时间可能有所改善,也可能没有改善在这种情况下,特别是由于并行性开销(例如线程,内存分配,同步等)。

现在,假设这是在Windows OS上运行的.NET应用程序,并且上述方法很适合您的情况,请考虑:

  • 增加最大连接数;
  • 禁用Nagle算法;

在下面的代码段中查找以更改应用程序配置。请注意:

  • 可以为maxconnection定义地址(例如https://stackoverflow.com),而不用使用“ *”
  • 建议在发布产品之前运行性能测试,以测试适用于maxconnection的适当配置。

                                         

https://docs.microsoft.com/en-us/dotnet/framework/configure-apps/file-schema/network/connectionmanagement-element-network-settings上找到有关连接管理的更多详细信息。