gpt4 book ai didi

java - 使用 Hibernate 的 ScrollableResults 慢慢读取 9000 万条记录

转载 作者:IT老高 更新时间:2023-10-28 12:56:19 25 4
gpt4 key购买 nike

我只需要使用 Hibernate 读取 MySQL 数据库中表中的每一行并基于它编写一个文件。但是有 9000 万行,而且非常大。因此,以下内容似乎是合适的:

ScrollableResults results = session.createQuery("SELECT person FROM Person person")
.setReadOnly(true).setCacheable(false).scroll(ScrollMode.FORWARD_ONLY);
while (results.next())
storeInFile(results.get()[0]);

问题是上面将尝试将所有 9000 万行加载到 RAM 中,然后再进入 while 循环......这会用 OutOfMemoryError: Java heap space exceptions 杀死我的内存:(。

所以我猜 ScrollableResults 不是我想要的?处理这个问题的正确方法是什么?我不介意这个 while 循环是否需要几天时间(我不希望这样)。

我想解决这个问题的唯一其他方法是使用 setFirstResult 和 setMaxResults 来遍历结果,并且只使用常规的 Hibernate 结果而不是 ScrollableResults。感觉好像它效率低下,并且当我在第 8900 万行调用 setFirstResult 时会开始花费相当长的时间......

更新:setFirstResult/setMaxResults 不起作用,结果需要很长时间才能达到我担心的偏移量。这里一定有解决办法!这不是一个非常标准的程序吗?我愿意放弃 Hibernate 并使用 JDBC 或任何它需要的东西。

更新 2:我想出的解决方案可以正常工作,但不是很好,基本上是以下形式:

select * from person where id > <offset> and <other_conditions> limit 1

由于我有其他条件,即使所有条件都在索引中,它仍然没有我希望的那么快......所以仍然欢迎其他建议..

最佳答案

使用 setFirstResult 和 setMaxResults 是我知道的唯一选择。

传统上,可滚动结果集只会根据需要将行传输到客户端。不幸的是,MySQL Connector/J 实际上是伪造的,它执行整个查询并将其传输到客户端,因此驱动程序实际上将整个结果集加载到 RAM 中,并将滴灌给您(您的内存不足问题证明了这一点) .你的想法是对的,这只是 MySQL java 驱动程序的缺点。

我没有办法解决这个问题,所以使用常规的 setFirst/max 方法加载大块。很抱歉带来坏消息。

只要确保使用无状态 session ,就没有 session 级缓存或脏跟踪等。

编辑:

除非您突破 MySQL J/Connector,否则您的 UPDATE 2 是您将获得的最好的。虽然没有理由不能提高查询的限制。如果您有足够的 RAM 来保存索引,这应该是一个便宜的操作。我会稍微修改一下,一次抓取一批,然后使用该批处理的最高 id 来抓取下一批。

注意:这仅在 other_conditions 使用相等(不允许范围条件)并将索引的最后一列作为 id 时才有效。

select * 
from person
where id > <max_id_of_last_batch> and <other_conditions>
order by id asc
limit <batch_size>

关于java - 使用 Hibernate 的 ScrollableResults 慢慢读取 9000 万条记录,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/2826319/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com