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

问题描述 投票:1回答:2

我们在云中实现了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秒内完成。似乎将传感器数据从传感器列表中取出是一个非常艰难的过程。如果我选择*(因此没有对传感器数据进行过滤),它也比我让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可以在几秒钟内查询数十万个文档,所以我很确定我的当前设置有问题。

有什么建议?

java mongodb azure azure-cosmosdb azure-cosmosdb-sqlapi
2个回答
1
投票

我无法为您的问题提供明确的解决方案,但希望能给您提供想法以获得具有所需性能级别的解决方案。

NoSql合适吗?

首先,为了摆脱困境,你确定你的场景非常适合noSQL吗?当主要场景使用精确定位数据时,CosmosDB会发光(创建,按id选择,按id更新,按id删除)。是的,它绝对可以进行有限的大规模操作和聚合,但查询数百万人正在推动它。另一方面,SQL设计用于处理大量数据,并且非常适合进行聚合。

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

调试硬数据

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

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

此外,加载38000个文档很可能永远不会一次性到达,检查实际对cosmosDB服务器进行了多少次继续查询。

此外,运行一个分析器并确保瓶颈确实存在于CosmosDB中。如果您正在进行许多延续呼叫并同时查询许多设备,那么客户端中也可能发生很多事情,并且在网络上进行查询。确保您不受客户端限制(GC,Http堆栈,内部锁定,连接/线程池等)。

数据/查询设计

Reduce queried data

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

Reduce model object size

/ *大约200多个键值对* /

这是一个巨大的目标。我会测试是否将它拆分为更小的对象将有助于cosmosDB在内部加载和处理文档时花费更少的时间。例如:

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

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

Sensors array?

查询仅查询第一个第一个测量集。阵列是否必要?您可以测试省略此级别是否会对性能产生任何影响。

Data types in model

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

应用程序设计

你真的每次都需要38000或者数百万的文件吗?考虑一下你是否可以使用子集

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

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


1
投票

传感器数据在运行时从文档中提取。因此,有效地解析和处理字符串blob。将向您收取提取传感器字段所需的资源消耗。

当你运行select *时,查询只返回整个blob,因此不需要解析。

当select仅包括已编制索引的字段时。索引数据很可能满足查询。因此,无需访问文档数据。

我会尝试两件事。在索引策略中包含传感器路径。这将增加查询引擎仅通过访问索引结构来处理查询的概率。

二,卸载顺序,这将进一步减少服务器端处理。

© www.soinside.com 2019 - 2024. All rights reserved.