C# 如何在azure表存储中使用partitionkey加速查询
如何提高此查询的速度?C# 如何在azure表存储中使用partitionkey加速查询,c#,azure,azure-table-storage,azure-virtual-network,azure-tablequery,C#,Azure,Azure Table Storage,Azure Virtual Network,Azure Tablequery,如何提高此查询的速度? var over1000Results = table.ExecuteQueryAsync(treanslationsQuery).Result.Cast<Translation>(); return over1000Results.Where(x => x.expireAt > DateTime.Now) .Where(x => x.effectiveAt <
var over1000Results = table.ExecuteQueryAsync(treanslationsQuery).Result.Cast<Translation>();
return over1000Results.Where(x => x.expireAt > DateTime.Now)
.Where(x => x.effectiveAt < DateTime.Now);
在执行以下查询的1-2分钟内,我们大约有100名消费者。这些运行中的每一次都代表消费函数的一次运行
TableQuery<T> treanslationsQuery = new TableQuery<T>()
.Where(
TableQuery.CombineFilters(
TableQuery.GenerateFilterCondition("PartitionKey", QueryComparisons.Equal, sourceDestinationPartitionKey)
, TableOperators.Or,
TableQuery.GenerateFilterCondition("PartitionKey", QueryComparisons.Equal, anySourceDestinationPartitionKey)
)
);
TableQuery-treanslationquery=newtablequery()
.在哪里(
TableQuery.CombineFilters(
TableQuery.GenerateFilterCondition(“PartitionKey”,QueryComparisons.Equal,sourceDestinationPartitionKey)
,表格操作员。或,
TableQuery.GenerateFilterCondition(“PartitionKey”,QueryComparisons.Equal,anySourceDestinationPartitionKey)
)
);
此查询将产生大约5000个结果。
完整代码:
public static async Task<IEnumerable<T>> ExecuteQueryAsync<T>(this CloudTable table, TableQuery<T> query) where T : ITableEntity, new()
{
var items = new List<T>();
TableContinuationToken token = null;
do
{
TableQuerySegment<T> seg = await table.ExecuteQuerySegmentedAsync(query, token);
token = seg.ContinuationToken;
items.AddRange(seg);
} while (token != null);
return items;
}
public static IEnumerable<Translation> Get<T>(string sourceParty, string destinationParty, string wildcardSourceParty, string tableName) where T : ITableEntity, new()
{
var acc = CloudStorageAccount.Parse(Environment.GetEnvironmentVariable("conn"));
var tableClient = acc.CreateCloudTableClient();
var table = tableClient.GetTableReference(Environment.GetEnvironmentVariable("TableCache"));
var sourceDestinationPartitionKey = $"{sourceParty.ToLowerTrim()}-{destinationParty.ToLowerTrim()}";
var anySourceDestinationPartitionKey = $"{wildcardSourceParty}-{destinationParty.ToLowerTrim()}";
TableQuery<T> treanslationsQuery = new TableQuery<T>()
.Where(
TableQuery.CombineFilters(
TableQuery.GenerateFilterCondition("PartitionKey", QueryComparisons.Equal, sourceDestinationPartitionKey)
, TableOperators.Or,
TableQuery.GenerateFilterCondition("PartitionKey", QueryComparisons.Equal, anySourceDestinationPartitionKey)
)
);
var over1000Results = table.ExecuteQueryAsync(treanslationsQuery).Result.Cast<Translation>();
return over1000Results.Where(x => x.expireAt > DateTime.Now)
.Where(x => x.effectiveAt < DateTime.Now);
}
公共静态异步任务ExecuteQueryAsync(此CloudTable表,TableQuery查询),其中T:ITableEntity,new()
{
var items=新列表();
TableContinuationToken=空;
做
{
TableQuerySegment seg=wait table.ExecuteQuerySegmentedAsync(查询,令牌);
令牌=seg.ContinuationToken;
项目。添加范围(seg);
}while(令牌!=null);
退货项目;
}
公共静态IEnumerable Get(string sourceParty、string destinationParty、string wildcardSourceParty、string tableName),其中T:ITableEntity,new()
{
var acc=CloudStorageAccount.Parse(Environment.GetEnvironmentVariable(“conn”));
var tableClient=acc.CreateCloudTableClient();
var table=tableClient.GetTableReference(Environment.GetEnvironmentVariable(“TableCache”));
var sourceDestinationPartitionKey=$“{sourceParty.ToLowerTrim()}-{destinationParty.ToLowerTrim()}”;
var anySourceDestinationPartitionKey=$“{wildcardSourceParty}-{destinationParty.ToLowerTrim()}”;
TableQuery-TreanslationQuery=新建TableQuery()
.在哪里(
TableQuery.CombineFilters(
TableQuery.GenerateFilterCondition(“PartitionKey”,QueryComparisons.Equal,sourceDestinationPartitionKey)
,表格操作员。或,
TableQuery.GenerateFilterCondition(“PartitionKey”,QueryComparisons.Equal,anySourceDestinationPartitionKey)
)
);
var over1000Results=table.ExecuteQueryAsync(treanslationquery.Result.Cast();
返回超过1000个结果。其中(x=>x.expireAt>DateTime.Now)
其中(x=>x.effectiveAt
在这些执行过程中,当有100个消费者时,如您所见,请求将群集并形成峰值:
在这些峰值期间,请求通常需要超过1分钟:
如何提高此查询的速度?var over1000Results=table.ExecuteQueryAsync(treanslationquery.Result.Cast();
var over1000Results = table.ExecuteQueryAsync(treanslationsQuery).Result.Cast<Translation>();
return over1000Results.Where(x => x.expireAt > DateTime.Now)
.Where(x => x.effectiveAt < DateTime.Now);
返回超过1000个结果。其中(x=>x.expireAt>DateTime.Now)
其中(x=>x.effectiveAt
这里有一个问题,您正在运行查询,然后使用这些“where”从内存中过滤它。在查询运行之前将筛选器移动到,这将非常有帮助
其次,您必须提供从数据库检索的行数限制不幸的是,下面的查询引入了一个完整表扫描:
TableQuery<T> treanslationsQuery = new TableQuery<T>()
.Where(
TableQuery.CombineFilters(
TableQuery.GenerateFilterCondition("PartitionKey", QueryComparisons.Equal, sourceDestinationPartitionKey)
, TableOperators.Or,
TableQuery.GenerateFilterCondition("PartitionKey", QueryComparisons.Equal, anySourceDestinationPartitionKey)
)
);
TableQuery-treanslationquery=newtablequery()
.在哪里(
TableQuery.CombineFilters(
TableQuery.GenerateFilterCondition(“PartitionKey”,QueryComparisons.Equal,sourceDestinationPartitionKey)
,表格操作员。或,
TableQuery.GenerateFilterCondition(“PartitionKey”,QueryComparisons.Equal,anySourceDestinationPartitionKey)
)
);
您应该将其拆分为两个分区键筛选器并分别查询它们,这将成为两个分区扫描,执行效率更高。您可以考虑三件事:
1。首先,去掉对查询结果执行的Where
子句。最好在查询中尽可能多地包含子句(如果您的表中有任何索引也包含子句,则更好)。现在,您可以按如下方式更改查询:
var translationsQuery = new TableQuery<T>()
.Where(TableQuery.CombineFilters(
TableQuery.CombineFilters(
TableQuery.GenerateFilterCondition("PartitionKey", QueryComparisons.Equal, sourceDestinationPartitionKey),
TableOperators.Or,
TableQuery.GenerateFilterCondition("PartitionKey", QueryComparisons.Equal, anySourceDestinationPartitionKey)
),
TableOperators.And,
TableQuery.CombineFilters(
TableQuery.GenerateFilterConditionForDate("affectiveAt", QueryComparisons.LessThan, DateTime.Now),
TableOperators.And,
TableQuery.GenerateFilterConditionForDate("expireAt", QueryComparisons.GreaterThan, DateTime.Now))
));
然后您可以在Get
方法中调用它:
return table.ExecuteQueryAsync(translationsQuery).Cast<Translation>();
返回table.ExecuteQueryAsync(translationsQuery.Cast();
正如您所看到的,方法本身不是异步的(您应该更改它的名称)并且是并行的。ForEach与传入异步方法不兼容。这就是为什么我使用了ExecuteQuerySegmented
。但是,为了使其性能更高并利用异步方法的所有优点,您可以将上述ForEach
循环替换为中的ActionBlock
方法或中的ParallelForEachAsync
扩展方法
2。执行独立的并行查询,然后合并结果是一个不错的选择,即使其性能提高最多10%。这使您有时间找到性能最佳的查询。但是,永远不要忘记在其中包含所有约束,并测试两种方法,以确定哪种方法更适合您的问题。
3。我不确定这是不是一个好建议,但去做吧,看看结果如何。如中所述:
表服务强制服务器超时,如下所示:
- 查询操作:在超时时间间隔内,可能会执行以下查询:
最多五秒钟。如果查询未在
在五秒钟的时间间隔内,响应包括延续标记
用于检索后续请求中的剩余项。参见查询
有关详细信息,请参阅超时和分页
- 插入、更新和删除