我正在寻找一种方法如何在合理的时间内处理从数据库加载的大量数据。
我面临的问题是我必须从数据库中读取所有数据(目前大约有 30M 行),然后用 Java 处理它们。处理本身不是问题,但从数据库中获取数据才是问题。提取通常需要 1-2 分钟。但是,我需要它比这快得多。我使用以下查询将数据从数据库直接加载到 DTO:
select id, id_post, id_comment, col_a, col_b from post_comment
其中 id
是主键,id_post
和 id_comment
是各自表的外键,col_a
和 col_b
是小型 int 数据类型的列。带有外键的列有索引。
我目前在工作中使用的工具是 Java、Spring Boot、Hibernate 和 PostgreSQL。
到目前为止,我想到的唯一选择是
- 为这个查询放弃 hibernate ,并尝试使用普通的 jdbc 连接,希望它会更快。
- 将处理算法从 Java 完全重写为 SQL 过程。
我是否遗漏了什么或者这些是我唯一的选择?我愿意接受任何想法。 请注意,我只需要读取数据,而不是以任何方式更改它们。
编辑:所用查询的解释分析
"Seq Scan on post_comment (cost=0.00..397818.16 rows=21809216 width=28) (actual time=0.044..6287.066 rows=21812469 loops=1), Planning Time: 0.124 ms, Execution Time: 8237.090 ms"
最佳答案
您需要一次处理所有行,还是可以一次处理一行?
如果您可以一次处理一个,您应该尝试使用可滚动的结果集。
org.hibernate.Query query = ...;
query.setReadOnly(true);
ScrollableResults sr = query.scroll(ScrollMode.FORWARD_ONLY);
while(sr.next())
{
MyClass myObject = (MyClass)sr.get()[0];
... process row for myObject ...
}
这将仍然记住实体管理器中的每个对象,因此会变得越来越慢。为避免该问题,您可以在完成后从实体管理器中分离对象。这只能在对象未被修改的情况下完成。如果修改了它们,则不会保留更改。
org.hibernate.Query query = ...;
query.setReadOnly(true);
ScrollableResults sr = query.scroll(ScrollMode.FORWARD_ONLY);
while(sr.next())
{
MyClass myObject = (MyClass)sr.get()[0];
... process row for myObject ...
entityManager.detach(myObject);
}
关于java - 处理来自 PostgreSQL 的大量数据,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/54874407/