开发者社区> 问答> 正文

使用Hibernate的ScrollableResults缓慢读取9000万条记录?mysql

我只需要使用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堆空间异常:(。

所以我想ScrollableResults不是我想要的吗?处理此问题的正确方法是什么?我不在乎这个while循环是否需要几天的时间(好吧,我不希望这样)。

我猜想解决此问题的唯一其他方法是使用setFirstResult和setMaxResults遍历结果,并且仅使用常规的Hibernate结果而不是ScrollableResults。感觉好像效率低下,并且当我在第89百万行上调用setFirstResult时,它将花费可笑的长时间。

更新:setFirstResult / setMaxResults不起作用,事实证明我花了很长的时间才能达到我所担心的偏移量。这里一定有解决方案!这不是一个很标准的程序吗?我愿意放弃Hibernate并使用JDBC或其他方法。

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

select * from person where id > and <other_conditions> limit 1 由于我还有其他条件,即使所有条件都在索引中,它仍然不如我希望的那样快...因此仍然欢迎其他建议。

展开
收起
保持可爱mmm 2020-05-17 10:15:00 643 0
1 条回答
写回答
取消 提交回答
  • 我知道,使用setFirstResult和setMaxResults是您唯一的选择。

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

    我没有办法解决这个问题,因此使用常规的setFirst / max方法加载大块数据。对不起,带来坏消息。

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

    编辑:

    除非您脱离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>来源:stack overflow

    2020-05-17 10:23:05
    赞同 展开评论 打赏
问答排行榜
最热
最新

相关电子书

更多
阿里云MySQL云数据库产品体系介绍 立即下载
One Box: 解读事务与分析一体化数据库 HybridDB for MySQL 立即下载
One Box:解读事务与分析一体化数据库HybridDB for MySQL 立即下载

相关镜像