首页 > 解决方案 > MongoDB Java API 读取速度慢

问题描述

我们正在从本地 MongoDB 读取集合中的所有文档,性能不是很出色。

我们需要转储所有数据,不要担心为什么,只要相信它确实需要并且没有解决办法。

我们有 4mio 文档,看起来像:

{
    "_id":"4d094f58c96767d7a0099d49",
    "exchange":"NASDAQ",
    "stock_symbol":"AACC",
    "date":"2008-03-07",
    "open":8.4,
    "high":8.75,
    "low":8.08,
    "close":8.55,
    "volume":275800,
    "adj close":8.55
}

我们现在使用这个简单的代码来阅读:

MongoClient mongoClient = MongoClients.create();
MongoDatabase database = mongoClient.getDatabase("localhost");
MongoCollection<Document> collection = database.getCollection("test");

MutableInt count = new MutableInt();
long start = System.currentTimeMillis();
collection.find().forEach((Block<Document>) document -> count.increment() /* actually something more complicated */ );
long start = System.currentTimeMillis();

我们以 16 秒(250k 行/秒)的速度读取整个集合,这对于小文档来说真的一点也不令人印象深刻。请记住,我们要加载 800mio 行。没有聚合、map reduce 或类似的可能。

这是否与 MongoDB 一样快,或者是否有其他方法可以更快地加载文档(其他技术、移动 Linux、更多 RAM、设置……)?

标签: javamongodbperformancemongodb-javamongo-java

解决方案


您没有指定您的用例,因此很难告诉您如何调整查询。(即:谁愿意一次加载 8 亿行只是为了计数?)。

鉴于您的架构,我认为您的数据几乎是只读的,并且您的任务与数据聚合有关。

您当前的工作只是读取数据,(很可能您的驱动程序将批量读取),然后停止,然后执行一些计算(地狱是的,一个 int 包装器用于更多地增加处理时间),然后重复。这不是一个好方法。如果您不以正确的方式访问数据库,它就不会神奇地快速。

如果计算不是太复杂,我建议你使用聚合框架而不是全部加载到你的 RAM 中。

您应该考虑改善聚合的一些事情:

  1. 将您的数据集划分为较小的集合。(例如:分区date,分区exchange...)。添加索引以支持该分区并在分区上操作聚合然后组合结果(典型的分治法)
  2. 项目仅需要的字段
  3. 过滤掉不必要的文件(如果可能的话)
  4. 如果您无法在内存上执行聚合(如果您达到每个管道 100MB 的限制),请允许使用磁盘。
  5. 使用内置管道来加速你的计算(例如:$count你的例子)

如果您的计算太复杂而无法使用聚合框架来表达,请使用mapReduce. 它在mongod进程上运行,数据不需要通过网络传输到您的内存中。

更新

所以看起来你想做一个 OLAP 处理,而你停留在 ETL 步骤。

您不需要也必须避免每次都将整个 OLTP 数据加载到 OLAP。只需要将新的更改加载到您的数据仓库。然后首先数据加载/转储需要更多时间是正常且可以接受的。

首次加载时,应考虑以下几点:

  1. 分而治之,再次将您的数据分解为较小的数据集(使用日期/交换/股票标签等谓词......)
  2. 进行并行计算,然后组合你的结果(你必须正确地划分你的数据集)
  3. 批量计算而不是处理forEach:加载数据分区然后计算而不是逐个计算。

推荐阅读