当前位置: 首页 > 面试题库 >

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

司迪
2023-03-14
问题内容

我只需要使用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 > <offset> and <other_conditions> limit 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>


 类似资料:
  • 我有一个“Customer”表,它有将近120万条记录,其中一列是ntext类型的“customer_records ”,它包含xml数据。我需要在该列的所有现有记录中替换一个url值。我尝试了下面的替换查询,但是执行该查询需要大约20分钟的时间。 在更新期间,CPU 消耗被利用到最大,这引起了问题。在 120 万条记录中,实际更新的记录中有 60 万条记录,但查询需要读取每条记录以查找和替换 U

  • 问题内容: 我已经在hbm文件中添加了复合文件,如下所示 现在我想查询如下 我没有得到相同的结果,因为有一个引用EmployeeSignId的组合键。在这种情况下,如何创建条件查询? 我在下面尝试过但得到0条记录 问题答案: 问题已解决。 我尝试了下面的工作

  • 我需要使用Spring Data Cassandra从Cassandra数据库读取超过一百万条记录,并使用Spring Batch将其写入一个文件。现在我正在使用Spring data Cassandra的分页特性,但它似乎是在执行,然后过滤记录。这可能不是一个好的选择,因为该表将有超过一百万条记录,同时将它们全部加载到内存中会很糟糕。 我还需要将它与Spring Batch集成,这样我就能够将每

  • 在我的mac崩溃后,每次同步我都会收到错误消息: 错误:无法从缓存taskartifacts.bin(/users/me/development/projectname/.gradle/2.10/taskartifacts/taskartifacts.bin)中读取条目“:RandomModuleName:CompilereleaseShaders”。 >[ljava.lanava.lang.;可

  • 每次运行应用程序都必须启动iisexpress吗?

  • 问题内容: 我有以下只需1秒即可执行的sql查询: 但是我需要一个结果集来获取比率大于0的结果。因此,当我将查询更改为此时,需要7分钟的时间来执行: 为什么这会使查询时间从1秒增加到7分钟?由于b表很大,因此我什至尝试使用CTE,但这也没有提高性能。我认为使用CTE可以从中筛选出较小的一组值,因此应该更快一些,但这无济于事: 我不能包括执行计划,因为除了查询之外,我没有对数据库的权限。 问题答案: