我有一个cosmos集合,周围有28000个文档,并且我在DocumentClient上使用CreateDocumentQuery,条件是“ T”类型的属性。通过下面提到的不同类型的用法,我在获得结果方面的时间延迟差异很大。
案例1:
var docs2 =
_documentClient.CreateDocumentQuery<HeartRateDayRecordIdentifierData>(collectionUri).Where(x =>
x.SubjectDeviceInformation.StudyId == "TestStudy"
&& x.SubjectDeviceInformation.SiteId == "Site_._Street_23"
&& x.SubjectDeviceInformation.SubjectId == "Subject3"
&& x.SubjectDeviceInformation.DeviceId == "Device1"
&& x.DaySplit == "20181112").AsEnumerable().FirstOrDefault();
情况2:这是相同的代码和条件,但是这次,我正在使用函数变量来对where条件进行除法。
Func<HeartRateDayRecordIdentifierData, bool> searchOptions = x =>
x.SubjectDeviceInformation.StudyId == "TestStudy"
&& x.SubjectDeviceInformation.SiteId == "Site_._Street_23"
&& x.SubjectDeviceInformation.SubjectId == "Subject3"
&& x.SubjectDeviceInformation.DeviceId == "Device1"
&& x.DaySplit == "20181112";
var docs1 = _documentClient.CreateDocumentQuery<HeartRateDayRecordIdentifierData>(collectionUri)
.Where(searchOptions).AsEnumerable().FirstOrDefault();
第一种情况,它具有内联条件,条件返回时间少于一秒,而在第二种情况下,第二种情况,结果大约需要20-30秒这似乎有点奇怪。我不知道在条件内联和在条件间传递变量之间有什么区别。
如果有人对宇宙文档样本感兴趣:
{
"id": "TestStudy_Site_._Street_21_Subject1_Device1_20181217",
"AssemblyVersion": "1.2.3.0",
"DataItemId": "20181217/TestStudy_Site_._Street_21_Subject1_Device1_20181217",
"MessageType": "HeartRateDayDocumentIdentifier",
"TimeStamp": "2018-12-14T00:00:00",
"DaySplit": "20181217",
"SubjectDeviceInformation": {
"SubjectId": "Subject1",
"DeviceId": "Device1",
"StudyId": "TestStudy",
"SiteId": "Site_._Street_21"
}
}
,这是用于反序列化文档的模型: 内部类HeartRateDayRecordIdentifierData { 公开字串编号{组; }
public string AssemblyVersion { get; set; }
public string DataItemId { get; set; }
public string MessageType { get; set; }
public DateTime TimeStamp { get; set; }
public string DaySplit { get; set; }
public SubjectDeviceInformation SubjectDeviceInformation { get; set; }
}
internal class SubjectDeviceInformation
{
public string SubjectId { get; set; }
public string DeviceId { get; set; }
public string StudyId { get; set; }
public string SiteId { get; set; }
}
任何我在这里做错的建议。
答案 0 :(得分:1)
在两种情况下,您都以非最佳方式进行此操作。
您只想要第一个,如果没有匹配项,则为null。
但是,您正在通过调用AsEnumerable().FirstOrDefault()
来进行同步跨分区查询。
您的where子句也应该是Expression<Func<HeartRateDayRecordIdentifierData, bool>>
而不是Func
。
在两种情况下都会发生的事情是,首先您返回CosmosDB中的所有数据,然后LINQ进行内存中过滤以将数据返回给您。
相反,您应该使用while(query.HasMoreResults)
和query.ExecuteNextAsync()
方法来返回数据。
这是您的查询方式:
public async Task<HeartRateDayRecordIdentifierData> GetSomethingAsync()
{
var query =
_documentClient.CreateDocumentQuery<HeartRateDayRecordIdentifierData>(collectionUri).Where(x =>
x.SubjectDeviceInformation.StudyId == "TestStudy"
&& x.SubjectDeviceInformation.SiteId == "Site_._Street_23"
&& x.SubjectDeviceInformation.SubjectId == "Subject3"
&& x.SubjectDeviceInformation.DeviceId == "Device1"
&& x.DaySplit == "20181112").AsDocumentQuery();
while(query.HasMoreResults)
{
var results = await query.ExecuteNextAsync();
if(results.Any())
return results.First();
}
return null;
}
这样,SDK会执行最少的调用次数以匹配数据,并且不会在每个可能的文档中进行查询。
如果您需要进一步的解释,请告诉我,因为这非常棘手,并且示例对此并没有帮助。
您还可以抽象所有这些内容,如果使用Cosmonaut,则只需使用对象和.FirstOrDefaultAsync
方法。这样,您的整个代码可以更改为:
public async Task<HeartRateDayRecordIdentifierData> GetSomethingAsync()
{
return await cosmosStore.Query().Where(x =>
x.SubjectDeviceInformation.StudyId == "TestStudy"
&& x.SubjectDeviceInformation.SiteId == "Site_._Street_23"
&& x.SubjectDeviceInformation.SubjectId == "Subject3"
&& x.SubjectDeviceInformation.DeviceId == "Device1"
&& x.DaySplit == "20181112").FirstOrDefaultAsync();
}
您可以自行选择适合您的方式。 免责声明,我是宇航员的创造者。