java 一个Spring JDBC查询挂起访问一个大表,Spring Data JPA中的PagingAndSortingRepository能解决这个问题吗?

pgx2nnw8  于 2023-02-28  发布在  Java
关注(0)|答案(1)|浏览(114)

由我们手工创建的Java对象关系管理器发出的大型(1400万行)表上的select *经常挂起。

import org.mountsinai.foo.Entity;
import org.springframework.jdbc.core.RowMapper;
import java.sql.ResultSet;
import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate;

// aDataSource is defined ...
NamedParameterJdbcTemplate jdbcTemplate = new NamedParameterJdbcTemplate(aDataSource);

RowMapper<Entity> entityRowMapper = (ResultSet rs, int rowNum) -> {
    Entity entity = new Entity();
    entity.setDatabaseId(rs.getInt("id"));
    entity.setEntityId(rs.getString("entity_id"));
    entity.setFound(rs.getBoolean("found"));
        // Set 10 more fields ...
    return entity;
};
jdbcTemplate.query("select * from table;", entityRowMapper);

因此我们使用NamedParameterJdbcTemplate的查询(String sql,RowMapper rowMapper)方法,我们使用com.microsoft.sqlserver:mssql-jdbc的JDBC库。
查询将转到SLQ Server数据库。有时一切正常,尤其是当表很小时。但是当表很大(1400万行)时,jdbcTemplate.query经常挂起。在这种情况下,SQL Server Profiler对数据库的跟踪显示查询finished,正如我们所看到的

SP:StmtCompleted
RPC:Completed

EventClass是跟踪中的it。客户端不会引发异常。
我正在考虑尝试修复这个问题,方法是用PagingAndSortingRepository接口中使用Pageable的findAll调用替换间歇性失败的代码。
亚瑟

pqwbnv8z

pqwbnv8z1#

进行分页可能会解决这个问题,但是您不必为此使用JPA,也不会有什么帮助。
正如在评论中所讨论的,你的问题很可能是在内存中存储1400万个示例需要大量内存,当然,构建这些示例需要大量时间。
因此,分页可以通过将过程分解为块来帮助实现,但是使用当前的方法,只需将偏移量和限制合并到查询中,就可以轻松地实现这一点。
但是在大型表上分页可能会变慢,使用key based pagination可能会更有效,其中您选择按主键排序的每批n行,并在下一批中选择前一批最后一个id值之后的前n行。
一个可能效果更好的替代方法是使用RowCallbackHandler代替行Map器,在处理下一行之前完全处理一行。这样可以最大限度地减少内存中保存的数据,同时只运行一个查询。当然,这取决于您尝试如何处理所有数据,如果这是一个可行的方法。
如果您要进行分页,您可能需要了解Spring Batch,它是为这种处理而设计的。
JPA可能只是增加了每行的内存和性能成本,它通常不太适合处理如此大量的数据。

相关问题