Microsoft Azure Cosmos DocumentDB 最佳读取查询性能

伦斯·格罗恩维尔德

我们已经在云中实现了 Azure CosmosDB(带有 SQL API 的 MongoDB)数据库。通过java,我们想根据MongoDB中隐藏的数据生成报表。我对读取查询的性能还不太满意,我想知道我当前的设置可以改进什么。

就像说的那样,我使用 Java 来查询数据库。我使用 Microsoft Azure DocumentDB 库来查询数据库:

<dependency>
    <groupId>com.microsoft.azure</groupId>
    <artifactId>azure-documentdb</artifactId>
    <version>1.16.2</version>
</dependency>

目前,我能够获得的最佳性能是在大约 20 秒内查询内存中大约 38.000 个文档,配置为 50,000 RU/s(本地 Cosmos 模拟器)。我真的希望这能得到改进,因为我们可能很快就会查询数百万个文档。

我有一种感觉,我们存储数据的方式可能不是最佳的。每个文档现在如下所示:

{
    "deviceid": "xxx",
    "devicedata": {
        "datetime": "2018-08-28T00:00:02.104Z",
        "sensors": [
            {
                "p_A2": "93095",
                "p_A3": "303883",
                "p_batterycurrent": "4294967.10000",
                "p_batterygauge": "38.27700",
                "p_batteryvoltage": "13.59400",
                ** ... around 200 more key - value pairs ... **
            }
        ]
    },
    "id": "aa5d3cf5-10fa-48dd-a0d2-a536284eddac",
    "_rid": "PtEIANkbMQABAAAAAAAAAA==",
    "_self": "dbs/PtEIAA==/colls/PtEIANkbMQA=/docs/PtEIANkbMQABAAAAAAAAAA==/",
    "_etag": "\"00000000-0000-0000-4040-006a7f2501d4\"",
    "_attachments": "attachments/",
    "_ts": 1535619672
}

我们经常使用的查询如下所示:

SELECT c.deviceid, 
    c.devicedata.datetime, 
    c.devicedata.sensors[0].p_A2, 
    c.devicedata.sensors[0].p_A3,
    c.devicedata.sensors[0].p_batterycurrent,
    c.devicedata.sensors[0].s_humidity 
FROM c 
WHERE c.deviceid = 'xxx'
    AND c.devicedata.datetime >= '2018-08-28T00:00:00.000Z' 
    AND c.devicedata.datetime < '2018-08-30T00:00:00.000Z' 
order by c.devicedata.datetime desc

我根据 deviceId 削减了这些查询。因此,对于每个设备,我使用此查询运行一个线程。这似乎比具有单个查询的单个线程快得多。

上面这样的查询需要我们大约 20 秒。

但是我注意到,如果我只查询 deviceid 和 devicedata.datetime,查询会在 2 秒内完成。似乎从传感器列表中获取传感器数据是一个非常困难的 cookie。如果我执行 select * (因此不对传感器数据进行过滤),它也比让 SQL API 过滤掉传感器时更快:大约 15 秒。

我的问题是,我可以做些什么来改进这一点?我的文档列表太长了吗?有什么办法可以设置不同的吗?传感器键值对不是固定的,可能因设备而异。

一些更多的技术细节:我有一个无限的集合,分区在 /deviceid 上。我使用了 Azure 的标准索引策略(即对所有内容进行索引),并将传感器排除在外。

我已经尝试了这里描述的所有技巧:https : //docs.microsoft.com/en-us/azure/cosmos-db/performance-tips-java

这是我当前的 Java 设置,尽管我尝试了很多不同的东西:

//This piece of code is currently in a seperate thread. There is one thread per deviceId to query
documentClient = new DocumentClient(HOST, MASTER_KEY,
                 ConnectionPolicy.GetDefault(), ConsistencyLevel.Session);

FeedOptions options = new FeedOptions();
options.setEnableCrossPartitionQuery(true);

documentList = documentClient
    .queryDocuments(getAlldataCollection().getSelfLink(), query, options)
    .getQueryIterable().toList();

我很确定 MongoDB 可以在几秒钟内查询数十万个文档,所以我很确定我当前的设置有问题。

有什么建议么?

伊姆雷·普维尔

我无法为您的问题提供明确的解决方案,但希望为您提供获得所需性能水平的解决方案的想法。

NoSql 合适吗?

首先,为了解决这个问题,您确定您的场景非常适合 noSQL?当主要场景处理精确数据(创建、按 id 选择、按 id 更新、按 id 删除)时,CosmosDB 会大放异彩。是的,它绝对可以进行有限的大规模操作和聚合,但查询数百万正在推动它。另一方面,SQL 旨在处理大量数据,并且非常擅长进行聚合。

让我们假设这个设计决定是经过仔细权衡的,并且由于未提及的原因,noSQL 是最合适的。

调试硬数据

不要对本地 cosmosDB 模拟器进行性能测试别。这显然不是真实的(考虑网络、存储带宽/搜索时间、系统影响),而只是模拟它。您可能会得到非常具有误导性的结果。启动一个真正的测试实例

调试查询性能问题的第一步是启用query-execution-metrics并查看这 20 秒实际花在哪里。

另外,加载 38000 个文档很可能永远不会在单个批处理中到达,请检查实际对 cosmosDB 服务器进行了多少继续查询。

此外,运行分析器并确保瓶颈确实在 CosmosDB 中。如果您正在进行许多连续调用并同时在许多设备上进行查询,那么客户端也可能会发生很多情况,并且查询会在网络上飞扬。确保您没有在客户端(GC、Http 堆栈、内部锁定、连接/线程池等)中受到限制。

数据/查询设计

减少查询数据

如果你已经知道deviceid,那么不要查询它 38000+ 次——那只是镇流器。

减小模型对象大小

/* 大约 200 个以上的键值对 */

那是一个巨大的物体。我将测试将其拆分为更小的对象是否有助于 cosmosDB 在内部加载和处理文档上花费更少的时间。前任:

{
    "p_A2": "93095",
    "p_A3": "303883",
    "battery" : {
        "current": "4294967.10000",
        "gauge": "38.27700",
        "voltage": "13.59400"
    }
   ...
}

不确定 docDB 如何在内部存储文档(完整图形与子文档),但您可以测试它是否会产生影响。2s 与 20s 的差异如此之大,以至于暗示它可能是相关的。

传感器阵列?

该查询仅查询第一个第一个测量集。数组是必需的吗?您可以测试省略此级别是否对性能有任何影响。

模型中的数据类型

battery_current等将传感器测量数值存储为较长的字符串。如果它们总是数字,那么您可以将它们存储为数字,并减少服务器和客户端中的文档大小。客户端性能可能会受到更多影响(字符串 = 堆分配)。例如:"4294967.10000"在客户端 (UTF-16) 中是 13 个字符 = 26B。

应用程序设计

您真的每次都需要所有这些 38000 或数百万份文件吗?考虑一下你是否可以通过一个子集来解决..

如果这是用于数据移动,则考虑其他选项(数据工厂、更改提要处理)以增量传输测量值。如果这是按需应用程序需要,则考虑加载较小的时间范围(= 较少的文档)并使用缓存过去的时间范围。如果可以,请在缓存之前预先聚合结果。过去的传感器数据很可能不会改变。

与往常一样,请考虑您的 ROI 业务案例优化总是可能的,但有时调整业务需求而不是技术解决方案更有利。

本文收集自互联网,转载请注明来源。

如有侵权,请联系 [email protected] 删除。

编辑于
0

我来说两句

0 条评论
登录 后参与评论

相关文章

Azure DocumentDb错误“查询必须评估为IEnumerable”

异常:从DocumentDB查询时出现Microsoft.Azure.Documents.RequestRateTooLargeException

我的Azure DocumentDB文档类是否应该继承自Microsoft.Azure.Documents.Document?

Azure DocumentDB上的性能降低

读取可能不存在的Azure DocumentDB文档

找不到Azure DocumentDB读取文档资源

Microsoft Azure Cosmos DB与Microsoft Azure SQL数据库

Microsoft Cosmos DB(DocumentDB API)与Cosmos DB(Table API)

Microsoft Azure DocumentDB与Azure表存储

Azure搜索与Azure DocumentDB

在cosmos documentDB中是否存在带有搜索直到规则的查询

使用遍历查询Azure Cosmos DB图形

Cosmos Db库Microsoft.Azure.DocumentDB.Core(2.1.0)-实际REST调用

Azure Cosmos查询转换为列表

从Microsoft.Azure.DocumentDb迁移到Microsoft.Azure.Cosmos以进行数据访问。并非所有选项都可用

在Microsoft.Azure.Cosmos.Client上跨分区启用查询

抛出异常:“ Microsoft.Azure.Cosmos.CosmosException”,将批量导入JSON到Azure Cosmos DB时出现错误请求

无法使用Microsoft.EntityFrameworkCore.Cosmos连接到Azure Cosmos Db帐户-响应状态代码

升级到Microsoft.Azure.Cosmos.Table以访问Azure表存储后的性能下降

Azure Cosmos DB查询

使用Microsoft.Azure.Cosmos时如何获取已编译的查询

不支持Azure Cosmos DB查询

Azure函数异常-将日志写入表存储时出错:Microsoft.Azure.Cosmos.Table.StorageException

Azure DocumentDB-查询未返回结果

动态生成Azure DocumentDB的查询

在Azure DocumentDB的选择查询中获取重复记录

截断 cosmos 的 documentdb 集合(python)

com.microsoft.azure.documentdb.DocumentClientException 日期标头不符合要求的格式

使用 .Net SDK Microsoft.Azure.Cosmos 查询 Cosmos DB 以获取不同派生类型的列表