java - 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。如果我选择 *(因此不对传感器数据进行过滤),它也比让 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 可以在几秒钟内查询数十万个文档,所以我很确定我当前的设置有问题。
有什么建议么?
解决方案
传感器数据是在运行时从文档中提取的。如此有效地解析和处理字符串 blob。您需要为提取传感器字段所需的资源消耗付费。
当您运行 select * 时,查询只是返回整个 blob,因此不需要解析。
当 select 仅包含已索引的字段时。索引数据满足查询的可能性非常高。因此,无需访问文档数据。
我会尝试两件事。在索引策略中包含传感器路径。这将增加查询引擎仅通过访问索引结构就可以处理查询的概率。
二、remover order by,这样会进一步减少服务器端的处理。
推荐阅读
- css - 在 Laravel 5.8 中实现分页链接样式错误
- javascript - 当 Animated.View 有一个 Animated.ScrollView 作为孩子时,PanResponder 在 Android 上无法正常工作
- html - 如果我必须将文本拆分为多个 div,我将如何使 text-align 的行为方式与对单个文本的行为方式相同
- python - 使用 Keras fit_generator 训练后保存的模型无法正确给出预测
- java - 覆盖等于和等于之间有什么区别?
- excel - 如何插入一个要求输入日期的输入框,然后在该日期之后添加到行?
- javascript - 如何遍历 JavaScript 中的静态值(常量)列表?
- android - 无法生成用于在 Android Studio 中发布的签名 APK
- html - 在较小的屏幕上更改网格项目的顺序
- excel - 无法让 VBA 编辑现有超链接