我们正在从本地 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、设置...)?
最佳答案
您没有指定用例,因此很难告诉您如何调整查询。 (即:谁愿意一次加载 8 亿行只是为了计数?)。
鉴于您的架构,我认为您的数据几乎是只读的,并且您的任务与数据聚合有关。
您当前的工作只是读取数据,(很可能您的驱动程序将批量读取),然后停止,然后执行一些计算( hell 是的,一个 int 包装器用于更多地增加处理时间),然后重复。这不是一个好方法。如果您没有以正确的方式访问数据库,它就不会神奇地快速。
如果计算不是太复杂,我建议你使用aggregation framework而不是全部加载到您的 RAM 中。
您应该考虑改进聚合:
- 将您的数据集分成更小的集合。 (例如:按
date
分区,按exchange
分区...)。添加索引以支持该分区并在分区上操作聚合,然后组合结果(典型的分而治之方法) - 项目仅需要的字段
- 过滤掉不必要的文档(如果可能)
- 如果您无法在内存上执行聚合(如果您达到每个管道 100MB 的限制),请允许使用磁盘。
- 使用内置管道加快计算速度(例如:
$count
用于您的示例)
如果您的计算过于复杂,无法用聚合框架表达,请使用 mapReduce
.它在 mongod
进程上运行,数据不需要通过网络传输到您的内存中。
更新
所以看起来您想要进行 OLAP 处理,但您停留在 ETL 步骤。
您不需要也必须避免每次都将整个 OLTP 数据加载到 OLAP。只需要将新的更改加载到您的数据仓库。那么第一次数据加载/转储需要更多时间是正常且可以接受的。
首次加载时,应考虑以下几点:
- 分而治之,再次将您的数据分解为更小的数据集(使用日期/交易所/股票标签等谓词...)
- 进行并行计算,然后合并结果(您必须正确划分数据集)
- 批量计算而不是
forEach
中的处理:加载数据分区然后计算而不是一个一个地计算。
关于java - MongoDB Java API 读取速度慢,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/52101372/