即使ExecuteNextAsync
返回true,IDocumentQuery上的HasMoreResults
似乎也没有返回任何结果。随后对ExecuteNextAsync
的调用意外返回数据。此外,ToList()
上的IQueryable
一致地返回数据。
这是生产代码中的行为变化,正确运行了一年多,这意味着ExecuteNextAsync
之前可靠地返回结果。
我已经将我的生产代码简化为可重复的测试用例。查询组合似乎对ExecuteNextAsync
的行为有影响(即在返回结果之前进行一次或多次调用)。例如,如果我执行id + partitionKey查找,它会按预期工作。
相关依赖:
<TargetFramework>netcoreapp2.0</TargetFramework>
<PackageReference Include="Microsoft.Azure.DocumentDB.Core" Version="2.3.0" />
我研究了以下没有帮助的内容:
这是一个演示该问题的最小测试:
using System;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Microsoft.Azure.Documents;
using Microsoft.Azure.Documents.Client;
using Microsoft.Azure.Documents.Linq;
using Newtonsoft.Json;
namespace ConsoleApp1
{
class Program
{
static void Main(string[] args)
{
Program.Run(args).GetAwaiter().GetResult();
}
static string endpointUrl = "xxxxx";
static string authKeyOrResourceToken = "xxxxx";
static Uri collectionUri = UriFactory.CreateDocumentCollectionUri("xxxxx", "xxxxx");
static async Task Run(string[] args)
{
ConnectionPolicy connectionPolicy = new ConnectionPolicy();
DocumentClient client = new DocumentClient(new Uri(endpointUrl), authKeyOrResourceToken, connectionPolicy, ConsistencyLevel.BoundedStaleness);
await Program.Test(client);
}
public static async Task Test(DocumentClient client)
{
FeedOptions feedOptions = new FeedOptions()
{
EnableCrossPartitionQuery = true,
MaxDegreeOfParallelism = -1,
MaxBufferedItemCount = 1,
MaxItemCount = 1,
PopulateQueryMetrics = true,
};
StringBuilder sql = new StringBuilder();
sql.AppendLine(" SELECT c.editionBudgetOrderGroupID, c.items, c.artifactType, c.level, c.editionID, c.sectionID, c.parentContentRef");
sql.AppendLine(" FROM c ");
sql.AppendLine(" JOIN items IN c.items ");
sql.AppendLine(" WHERE ");
sql.AppendLine(" c.artifactType = @artifactType ");
sql.AppendLine(" AND items.contentID = @childContentId ");
sql.AppendLine(" AND c.level = @level");
sql.AppendLine(" AND c.tenant = @tenantId");
SqlParameterCollection sqlParams = new SqlParameterCollection
{
new SqlParameter("@artifactType", "EditionBudgetOrderGroup"),
new SqlParameter("@tenantId", "xxx"),
new SqlParameter("@childContentId", "xxxxx"),
new SqlParameter("@level", "ContentItemLevel")
};
SqlQuerySpec sqlSpec = new SqlQuerySpec
{
QueryText = sql.ToString(),
Parameters = sqlParams,
};
// this is ok
Document thisIsOk1 = client.CreateDocumentQuery<Document>(
collectionUri,
sqlSpec,
feedOptions).ToList().FirstOrDefault();
// this is ok
Document thisIsOk2 = client.CreateDocumentQuery<Document>(
collectionUri,
sqlSpec,
feedOptions).AsEnumerable().FirstOrDefault();
// This is normally called by the calling method, value returned is null
IDocumentQuery<Document> result = client.CreateDocumentQuery<Document>(
collectionUri,
sqlSpec,
feedOptions).AsDocumentQuery();
Console.WriteLine($"result.HasMoreResults: {result.HasMoreResults}");
FeedResponse<Document> feedResponse1 = await result.ExecuteNextAsync<Document>();
IList<Document> thisIsNullList = feedResponse1.ToList();
Console.WriteLine($"thisIsNullList?.Count : {thisIsNullList?.Count}");
Document thisIsNull = feedResponse1.FirstOrDefault();
// this is ok - calling ExecuteNextAsync causes expected result
FeedResponse<Document> feedResponse2 = await result.ExecuteNextAsync<Document>();
Document thisIsOk3 = feedResponse2.FirstOrDefault();
Console.WriteLine($"thisIsOk1 == null : {thisIsOk1 == null}");
Console.WriteLine($"thisIsOk2 == null : {thisIsOk2 == null}");
Console.WriteLine($"thisIsNull == null : {thisIsNull == null}");
Console.WriteLine($"thisIsOk3 == null : {thisIsOk3 == null}");
string metrics1 = JsonConvert.SerializeObject(feedResponse1.QueryMetrics, Formatting.Indented);
string metrics2 = JsonConvert.SerializeObject(feedResponse2.QueryMetrics, Formatting.Indented);
Console.WriteLine($"feedResponse1.QueryMetrics: {metrics1}");
Console.WriteLine($"feedResponse2.QueryMetrics: {metrics2}");
}
}
}
result.HasMoreResults: True
thisIsNullList?.Count : 0
我期待thisIsNull
有一个值,因为HasMoreResults是True。
thisIsOk1 == null : False
thisIsOk2 == null : False
thisIsNull == null : True
thisIsOk3 == null : False
以下是第一个和第二个ExecuteNextAsync
操作的查询指标。有时第二个操作没有像下面那样的指标,有时候它没有填充。
feedResponse1.QueryMetrics: {
"1": {
"TotalTime": "00:00:00.0017400",
"RetrievedDocumentCount": 0,
"RetrievedDocumentSize": 0,
"OutputDocumentCount": 0,
"QueryPreparationTimes": {
"CompileTime": "00:00:00.0001300",
"LogicalPlanBuildTime": "00:00:00.0000700",
"PhysicalPlanBuildTime": "00:00:00.0001400",
"QueryOptimizationTime": "00:00:00.0000100"
},
"QueryEngineTimes": {
"IndexLookupTime": "00:00:00.0011200",
"DocumentLoadTime": "00:00:00",
"WriteOutputTime": "00:00:00",
"RuntimeExecutionTimes": {
"SystemFunctionExecutionTime": "00:00:00",
"UserDefinedFunctionExecutionTime": "00:00:00",
"TotalTime": "00:00:00.0000300"
}
},
"Retries": 0,
"ClientSideMetrics": {
"Retries": 0,
"RequestCharge": 11.83,
"FetchExecutionRanges": [
{
"ActivityId": "660e25e9-0904-4f97-a627-f836422151f3",
"StartTime": "2019-05-01T19:38:07.0354836Z",
"EndTime": "2019-05-01T19:38:07.0642583Z",
"PartitionId": "1",
"NumberOfDocuments": 0,
"RetryCount": 0
}
],
"PartitionSchedulingTimeSpans": [
{
"Item1": "1",
"Item2": {
"NumPreemptions": 1,
"TurnaroundTime": "00:00:00.0289540",
"ResponseTime": "00:00:00.0000617",
"RunTime": "00:00:00.0287753",
"WaitTime": "00:00:00.0001791"
}
}
]
},
"IndexHitRatio": 1.0
},
"2": {
"TotalTime": "00:00:00.0016100",
"RetrievedDocumentCount": 1,
"RetrievedDocumentSize": 1356,
"OutputDocumentCount": 1,
"QueryPreparationTimes": {
"CompileTime": "00:00:00.0001300",
"LogicalPlanBuildTime": "00:00:00.0000800",
"PhysicalPlanBuildTime": "00:00:00.0001500",
"QueryOptimizationTime": "00:00:00.0000200"
},
"QueryEngineTimes": {
"IndexLookupTime": "00:00:00.0009200",
"DocumentLoadTime": "00:00:00.0000300",
"WriteOutputTime": "00:00:00",
"RuntimeExecutionTimes": {
"SystemFunctionExecutionTime": "00:00:00",
"UserDefinedFunctionExecutionTime": "00:00:00",
"TotalTime": "00:00:00.0000500"
}
},
"Retries": 0,
"ClientSideMetrics": {
"Retries": 0,
"RequestCharge": 12.8,
"FetchExecutionRanges": [
{
"ActivityId": "3fc13562-1f3a-4636-ac54-492d01040dcb",
"StartTime": "2019-05-01T19:38:07.035552Z",
"EndTime": "2019-05-01T19:38:07.0634899Z",
"PartitionId": "2",
"NumberOfDocuments": 1,
"RetryCount": 0
}
],
"PartitionSchedulingTimeSpans": [
{
"Item1": "2",
"Item2": {
"NumPreemptions": 1,
"TurnaroundTime": "00:00:00.0281628",
"ResponseTime": "00:00:00.0000935",
"RunTime": "00:00:00.0279391",
"WaitTime": "00:00:00.0002242"
}
}
]
},
"IndexHitRatio": 1.0
}
}
feedResponse2.QueryMetrics: {}
我已经确定这是SDK中的一个错误。降级到Microsoft.Azure.DocumentDB.Core 2.2.2
解决了这个问题。 thisIsNull
不再等于null。 SDK问题似乎已在2.2.3
中引入,也是2.3.0
中的一个问题
<PackageReference Include="Microsoft.Azure.DocumentDB.Core" Version="2.2.2" />
这是更新后的输出:
result.HasMoreResults: True
thisIsNullList?.Count : 1
thisIsOk1 == null : False
thisIsOk2 == null : False
thisIsNull == null : False
thisIsOk3 == null : False
feedResponse1.QueryMetrics: {
"2": {
"TotalTime": "00:00:00.0016100",
"RetrievedDocumentCount": 1,
"RetrievedDocumentSize": 1356,
"OutputDocumentCount": 1,
"QueryPreparationTimes": {
"CompileTime": "00:00:00.0002000",
"LogicalPlanBuildTime": "00:00:00.0000600",
"PhysicalPlanBuildTime": "00:00:00.0000900",
"QueryOptimizationTime": "00:00:00.0000100"
},
"QueryEngineTimes": {
"IndexLookupTime": "00:00:00.0009300",
"DocumentLoadTime": "00:00:00.0000300",
"WriteOutputTime": "00:00:00",
"RuntimeExecutionTimes": {
"SystemFunctionExecutionTime": "00:00:00",
"UserDefinedFunctionExecutionTime": "00:00:00",
"TotalTime": "00:00:00.0000500"
}
},
"Retries": 0,
"ClientSideMetrics": {
"Retries": 0,
"RequestCharge": 12.8,
"FetchExecutionRanges": [
{
"ActivityId": "cca905f5-cb83-49a0-a964-de56430725d1",
"StartTime": "2019-05-01T21:35:53.0457606Z",
"EndTime": "2019-05-01T21:35:53.0713622Z",
"PartitionId": "2",
"NumberOfDocuments": 1,
"RetryCount": 0
}
],
"PartitionSchedulingTimeSpans": [
{
"Item1": "2",
"Item2": {
"NumPreemptions": 1,
"TurnaroundTime": "00:00:00.0259268",
"ResponseTime": "00:00:00.0002747",
"RunTime": "00:00:00.0256023",
"WaitTime": "00:00:00.0003246"
}
}
]
},
"IndexHitRatio": 1.0
},
"1": {
"TotalTime": "00:00:00.0017500",
"RetrievedDocumentCount": 0,
"RetrievedDocumentSize": 0,
"OutputDocumentCount": 0,
"QueryPreparationTimes": {
"CompileTime": "00:00:00.0001200",
"LogicalPlanBuildTime": "00:00:00.0000900",
"PhysicalPlanBuildTime": "00:00:00.0001300",
"QueryOptimizationTime": "00:00:00.0000100"
},
"QueryEngineTimes": {
"IndexLookupTime": "00:00:00.0010900",
"DocumentLoadTime": "00:00:00",
"WriteOutputTime": "00:00:00",
"RuntimeExecutionTimes": {
"SystemFunctionExecutionTime": "00:00:00",
"UserDefinedFunctionExecutionTime": "00:00:00",
"TotalTime": "00:00:00.0000200"
}
},
"Retries": 0,
"ClientSideMetrics": {
"Retries": 0,
"RequestCharge": 11.83,
"FetchExecutionRanges": [
{
"ActivityId": "fded90c2-dacb-468e-97ad-58ddf28cb0eb",
"StartTime": "2019-05-01T21:35:53.0457474Z",
"EndTime": "2019-05-01T21:35:53.0701024Z",
"PartitionId": "1",
"NumberOfDocuments": 0,
"RetryCount": 0
}
],
"PartitionSchedulingTimeSpans": [
{
"Item1": "1",
"Item2": {
"NumPreemptions": 1,
"TurnaroundTime": "00:00:00.0246889",
"ResponseTime": "00:00:00.0002799",
"RunTime": "00:00:00.0243563",
"WaitTime": "00:00:00.0003328"
}
}
]
},
"IndexHitRatio": 1.0
}
}
feedResponse2.QueryMetrics: {
"1": {
"TotalTime": "00:00:00.0020400",
"RetrievedDocumentCount": 0,
"RetrievedDocumentSize": 0,
"OutputDocumentCount": 0,
"QueryPreparationTimes": {
"CompileTime": "00:00:00.0001200",
"LogicalPlanBuildTime": "00:00:00.0001400",
"PhysicalPlanBuildTime": "00:00:00.0001100",
"QueryOptimizationTime": "00:00:00.0000100"
},
"QueryEngineTimes": {
"IndexLookupTime": "00:00:00.0013600",
"DocumentLoadTime": "00:00:00",
"WriteOutputTime": "00:00:00",
"RuntimeExecutionTimes": {
"SystemFunctionExecutionTime": "00:00:00",
"UserDefinedFunctionExecutionTime": "00:00:00",
"TotalTime": "00:00:00.0000100"
}
},
"Retries": 0,
"ClientSideMetrics": {
"Retries": 0,
"RequestCharge": 11.83,
"FetchExecutionRanges": [
{
"ActivityId": "8e395b01-f970-4183-84fe-45f44f0ec1a5",
"StartTime": "2019-05-01T21:36:05.1121303Z",
"EndTime": "2019-05-01T21:36:05.1376982Z",
"PartitionId": "1",
"NumberOfDocuments": 0,
"RetryCount": 0
}
],
"PartitionSchedulingTimeSpans": [
{
"Item1": "1",
"Item2": {
"NumPreemptions": 1,
"TurnaroundTime": "00:00:00.0260265",
"ResponseTime": "00:00:00.0003902",
"RunTime": "00:00:00.0255689",
"WaitTime": "00:00:00.0004579"
}
}
]
},
"IndexHitRatio": 1.0
},
"2": {
"TotalTime": "00:00:00.0019200",
"RetrievedDocumentCount": 1,
"RetrievedDocumentSize": 1356,
"OutputDocumentCount": 1,
"QueryPreparationTimes": {
"CompileTime": "00:00:00.0001700",
"LogicalPlanBuildTime": "00:00:00.0001100",
"PhysicalPlanBuildTime": "00:00:00.0001700",
"QueryOptimizationTime": "00:00:00.0000100"
},
"QueryEngineTimes": {
"IndexLookupTime": "00:00:00.0011200",
"DocumentLoadTime": "00:00:00.0000400",
"WriteOutputTime": "00:00:00",
"RuntimeExecutionTimes": {
"SystemFunctionExecutionTime": "00:00:00",
"UserDefinedFunctionExecutionTime": "00:00:00",
"TotalTime": "00:00:00.0000400"
}
},
"Retries": 0,
"ClientSideMetrics": {
"Retries": 0,
"RequestCharge": 12.8,
"FetchExecutionRanges": [
{
"ActivityId": "7a5d1e18-aa15-4fa3-b68f-828dae99cd39",
"StartTime": "2019-05-01T21:36:05.1121553Z",
"EndTime": "2019-05-01T21:36:05.1377267Z",
"PartitionId": "2",
"NumberOfDocuments": 1,
"RetryCount": 0
}
],
"PartitionSchedulingTimeSpans": [
{
"Item1": "2",
"Item2": {
"NumPreemptions": 1,
"TurnaroundTime": "00:00:00.0259876",
"ResponseTime": "00:00:00.0003792",
"RunTime": "00:00:00.0255721",
"WaitTime": "00:00:00.0004157"
}
}
]
},
"IndexHitRatio": 1.0
}
}