CosmosDB:查询 CosmosDB 时的 Linq 与 SqlQuerySpec 性能

Lud*_*212 6 c# linq azure azure-cosmosdb

我在查询 CosmosDB 特定文档时定期执行 LINQ 谓词。然而,今天我的 CosmosDB 中填满了 10 万多个文档。表演非常缓慢。由于 Azure 门户中的 SQL 查询明显更快,因此我尝试使用 SqlQuerySpec。瞧\xc3\xa1!它的工作速度快得多。

\n\n

谁能告诉我在 CosmosDB 中使用 Linq 谓词时到底发生了什么以及为什么它会减慢我的查询速度?

\n\n

下面的代码在我的获取文档的方法中使用。\n注意:在本例中,id 是分区键。

\n\n
        var collectionUri = UriFactory.CreateDocumentCollectionUri(CDBdatabase, CDBcollection);\n\n        var sqlStatement = new SqlQuerySpec\n        {\n            QueryText = "SELECT * FROM c where c.id = @id",\n            Parameters = new SqlParameterCollection()\n                {\n                          new SqlParameter("@id", consumerId),\n                },\n        };\n\n        IDocumentQuery<T> query = documentClient.CreateDocumentQuery<T>(\n            collectionUri,\n            sqlStatement,\n            .AsDocumentQuery();\n\n        List<ConsumerDetails> results = new List<ConsumerDetails>();\n        while (query.HasMoreResults)\n        {\n            results.AddRange(await query.ExecuteNextAsync<ConsumerDetails>());\n        }\n\n        return results.FirstOrDefault();\n
Run Code Online (Sandbox Code Playgroud)\n\n

相对而言,较慢的代码:

\n\n
        return documentClient.CreateDocumentQuery<ConsumerDetails>(\n            collectionUri,\n            .Where(f => f.Id == consumerId).AsEnumerable().FirstOrDefault();\n
Run Code Online (Sandbox Code Playgroud)\n

Nic*_*sas 2

答案在于您查询的方式。

您发布的两个代码段不相同。

为了使它们相同,第二个必须如下所示:

var collectionUri = UriFactory.CreateDocumentCollectionUri(CDBdatabase, CDBcollection);

var query = documentClient.CreateDocumentQuery<ConsumerDetails>(
    collectionUri)
    .Where(f => f.Id == consumerId)
    .AsDocumentQuery();

List<ConsumerDetails> results = new List<ConsumerDetails>();
while (query.HasMoreResults)
{
    results.AddRange(await query.ExecuteNextAsync<ConsumerDetails>());
}

return results.FirstOrDefault();
Run Code Online (Sandbox Code Playgroud)

在这两种情况下,您将针对 CosmosDB 执行 SQL。然而,在 LINQ 情况下,LINQ 翻译器将启动将表达式转换为 SQL 查询。

同样在 SQL 示例中,由于您直接指向小写字母id(即 CosmosDB id),它也是分区键,CosmosDB 将识别这一点并将查询从跨分区查询限制为特定分区查询,从而使其更快、更高效。更便宜。(.Where(f => f.Id == consumerId)大写Id)一旦通过 LINQ 提供程序,就会被转换为SELECT * FROM c where c.Id = consumerId除非有JsonAttribute("id")修饰Id属性。这意味着您需要PartitionKeyFeedOptions查询中提供值。