Почему CosmosDB FeedResponse не содержит результатов, когда значение HasMoreResults равно True - PullRequest
1 голос
/ 01 мая 2019

ExecuteNextAsync в IDocumentQuery, похоже, не возвращает никаких результатов, даже если HasMoreResults возвращает true. Последующие вызовы 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: {}

1 Ответ

1 голос
/ 02 мая 2019

Я определил, что это ошибка в SDK.Понижение до Microsoft.Azure.DocumentDB.Core 2.2.2 решило проблему.thisIsNull больше не равно нулю.Проблема 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
  }
}
...