java - 如何批量选择所有表记录,并逐批处理?

标签 java postgresql hibernate

表中有超过 10,00,000 条记录,我正在处理。我需要为每条记录执行异步操作(推送队列)。一次获取所有记录并循环处理每条记录感觉像是一个坏主意。相反,我想分批获取记录并遍历每批。在互联网上的某处阅读有关使用 setFetchSize(int n) 进行批量查询的信息,我的 DAO 如下所示:

public List<UserPreferenceDTO> getUserPreferences() {
    String sqlQueryString = "select us.id as userId, pf.id as preferenceId from users us, preferences pf where us.id = pf.user_id;";
    SQLQuery sqlQuery = (SQLQuery) session.createSQLQuery(sqlQueryString).setFetchSize(200);
    return sqlQuery.addScalar("userId").addScalar("preferenceId").setResultTransformer(new AliasToBeanResultTransformer(UserPreferenceDTO.class)).list();
    }

我的服务类如下所示:

List<UserPreferenceDTO> userPreferenceDTOs = userDeviceDao.getUserPreferences();

    for(UserPreferenceDTO userPreferenceDTO: userPreferenceDTOs ){
         pushToRabbitMQ(userPreferenceDTO);
    }

我需要从数据库中获取“N”条记录,将它们推送到队列中进行处理,然后再获取“N”条记录将它们推送到队列中,依此类推,直到所有记录都推送到队列中。

最佳答案

合理的 setFetchSize() 在任何批量加载场景中都是必须的,因为数据库不必单独发送每一行。即使您与数据库的往返只是 10ms,它仍然需要 10ms * 10mln ~ 28 h 来完成所有行。改进通常稳定在 1000 左右,但这取决于您的环境设置,因此您需要对其进行测试。

.list() 替换为 .scroll() 可能就足够了,它返回 ScrollableResults 允许一次读取一条记录时间。然而,这将取决于数据库,有些像 MySQL will fake the scrolling and load the entire result set .

如果是这种情况,您需要在包含 setFirstResult()setMaxResult() 的查询中使用 ORDER BY。这将执行新查询以读取每个批处理。这是最安全的方法,但 ORDER BY 可能是一种昂贵的语句。

关于java - 如何批量选择所有表记录,并逐批处理?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/49676777/

相关文章:

java - 为什么我收到此错误 "Exception in thread "main"java.lang.ArrayIndexOutOfBoundsException : 1"

java - 将自定义适配器转换为在 Java 中使用泛型

java - 如何将 org.postgresql.geometric.PGpoint 映射到 Hibernate 类型

java - 使用枚举进行 HQL 查询

java - Hibernate DataIntegrityViolationException 外键违规不允许删除

javax.naming.NoInitialContextException : Need to specify class name in environment or system property

java - 证明迭代键的 `get` 非空

java - 每个 CollectionGroup 中的最新文档

sql - 如何自下而上遍历树以计算 PostgreSQL 中节点值的(加权)平均值?

python - Django AutoOneToOneField 迁移和现有条目