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

时间:2018-08-31 06:48:09

标签: java mongodb azure azure-cosmosdb azure-cosmosdb-sqlapi

我们已经在云中实现了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秒钟内完成。似乎将传感器数据从传感器列表中剔除是一个非常棘手的问题。如果我执行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可以在几秒钟内查询成千上万的文档,因此我可以肯定我在当前设置中做错了。

有什么建议吗?

2 个答案:

答案 0 :(得分:1)

我无法为您的问题提供确切的解决方案,但希望您能提供一些想法,以使解决方案达到所需的性能水平。

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或数百万个文档吗?考虑一下是否可以使用子集。

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

与往常一样,考虑您的投资回报率的业务案例。优化始终是可能的,但有时调整业务需求而不是技术解决方案更为有益。

答案 1 :(得分:1)

运行时正在从文档中提取传感器数据。因此有效地分析和处理了字符串blob。您需要支付提取传感器字段所需的资源消耗。

运行时,选择*查询只是返回整个blob,因此不需要解析。

当选择仅包含已索引的字段时。索引数据很有可能满足查询要求。因此,无需访问文档数据。

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

二,通过remove命令,这将进一步减少服务器端的处理。